From 6183b2736fae22b8bafb509e37386fa7a037c5f3 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Tue, 11 Feb 2014 10:19:17 +0000 Subject: QPID-5504 : refactring of queues, and introduce management node and amqp-management module git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1567026 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/amqp_1_0/jms/impl/DestinationImpl.java | 31 +- .../amqp_1_0/jms/impl/MessageConsumerImpl.java | 4 +- .../apache/qpid/amqp_1_0/jms/impl/MessageImpl.java | 17 +- .../amqp_1_0/jms/impl/MessageProducerImpl.java | 6 +- .../apache/qpid/amqp_1_0/jms/impl/QueueImpl.java | 20 +- .../qpid/amqp_1_0/jms/impl/QueueReceiverImpl.java | 8 +- .../apache/qpid/amqp_1_0/jms/impl/SessionImpl.java | 4 +- .../apache/qpid/amqp_1_0/jms/impl/TopicImpl.java | 20 +- .../amqp_1_0/jms/impl/TopicSubscriberImpl.java | 5 +- .../org/apache/qpid/amqp_1_0/client/Session.java | 92 +- .../qpid/server/exchange/AbstractExchange.java | 5 +- .../qpid/server/exchange/DefaultExchange.java | 5 +- .../qpid/server/message/MessageDestination.java | 5 +- .../qpid/server/message/MessageInstance.java | 8 +- .../apache/qpid/server/message/MessageSource.java | 14 +- .../server/message/internal/InternalMessage.java | 254 ++++ .../message/internal/InternalMessageHeader.java | 197 +++ .../message/internal/InternalMessageMetaData.java | 95 ++ .../internal/InternalMessageMetaDataType.java | 76 ++ .../qpid/server/model/AccessControlProvider.java | 2 - .../apache/qpid/server/model/AmqpManagement.java | 35 + .../qpid/server/model/AuthenticationProvider.java | 2 - .../java/org/apache/qpid/server/model/Binding.java | 2 - .../java/org/apache/qpid/server/model/Broker.java | 2 - .../apache/qpid/server/model/ConfiguredObject.java | 12 +- .../org/apache/qpid/server/model/Connection.java | 28 +- .../org/apache/qpid/server/model/Consumer.java | 2 - .../org/apache/qpid/server/model/Exchange.java | 18 +- .../java/org/apache/qpid/server/model/Group.java | 2 - .../org/apache/qpid/server/model/GroupMember.java | 2 - .../apache/qpid/server/model/GroupProvider.java | 2 - .../org/apache/qpid/server/model/KeyStore.java | 2 - .../java/org/apache/qpid/server/model/Plugin.java | 2 - .../java/org/apache/qpid/server/model/Port.java | 2 - .../qpid/server/model/PreferencesProvider.java | 2 - .../java/org/apache/qpid/server/model/Queue.java | 40 +- .../java/org/apache/qpid/server/model/Session.java | 2 - .../org/apache/qpid/server/model/TrustStore.java | 2 - .../java/org/apache/qpid/server/model/User.java | 2 - .../org/apache/qpid/server/model/VirtualHost.java | 39 +- .../qpid/server/model/adapter/QueueAdapter.java | 43 +- .../server/model/adapter/VirtualHostAdapter.java | 14 +- .../qpid/server/plugin/SystemNodeCreator.java | 1 + .../qpid/server/protocol/AMQSessionModel.java | 3 +- .../apache/qpid/server/queue/AMQPriorityQueue.java | 46 - .../org/apache/qpid/server/queue/AMQQueue.java | 26 +- .../apache/qpid/server/queue/AMQQueueFactory.java | 4 +- .../queue/AssignedConsumerMessageGroupManager.java | 27 +- .../org/apache/qpid/server/queue/BaseQueue.java | 4 +- .../apache/qpid/server/queue/ConflationQueue.java | 4 +- .../qpid/server/queue/ConflationQueueList.java | 65 +- .../queue/DefinedGroupMessageGroupManager.java | 48 +- .../qpid/server/queue/MessageGroupManager.java | 14 +- .../qpid/server/queue/OrderedQueueEntry.java | 78 ++ .../qpid/server/queue/OrderedQueueEntryList.java | 198 +++ .../apache/qpid/server/queue/OutOfOrderQueue.java | 14 +- .../apache/qpid/server/queue/PriorityQueue.java | 46 + .../qpid/server/queue/PriorityQueueList.java | 231 ++-- .../apache/qpid/server/queue/QueueConsumer.java | 48 +- .../qpid/server/queue/QueueConsumerList.java | 72 +- .../org/apache/qpid/server/queue/QueueContext.java | 20 +- .../org/apache/qpid/server/queue/QueueEntry.java | 9 +- .../apache/qpid/server/queue/QueueEntryImpl.java | 60 +- .../qpid/server/queue/QueueEntryIterator.java | 6 +- .../apache/qpid/server/queue/QueueEntryList.java | 16 +- .../qpid/server/queue/QueueEntryListFactory.java | 4 +- .../qpid/server/queue/QueueEntryVisitor.java | 6 +- .../apache/qpid/server/queue/SimpleAMQQueue.java | 299 ++--- .../qpid/server/queue/SimpleQueueEntryImpl.java | 78 -- .../qpid/server/queue/SimpleQueueEntryList.java | 220 +-- .../org/apache/qpid/server/queue/SortedQueue.java | 22 +- .../apache/qpid/server/queue/SortedQueueEntry.java | 143 ++ .../qpid/server/queue/SortedQueueEntryImpl.java | 143 -- .../qpid/server/queue/SortedQueueEntryList.java | 110 +- .../server/queue/SortedQueueEntryListFactory.java | 5 +- .../apache/qpid/server/queue/StandardQueue.java | 41 + .../qpid/server/queue/StandardQueueEntry.java | 45 + .../qpid/server/queue/StandardQueueEntryList.java | 57 + .../store/DurableConfigurationStoreHelper.java | 4 +- .../server/virtualhost/AbstractVirtualHost.java | 8 + ...g.apache.qpid.server.plugin.MessageMetaDataType | 19 + .../VirtualHostConfigurationTest.java | 12 +- .../qpid/server/exchange/TopicExchangeTest.java | 16 +- .../qpid/server/queue/AMQPriorityQueueTest.java | 116 -- .../qpid/server/queue/AMQQueueFactoryTest.java | 4 +- .../qpid/server/queue/ConflationQueueListTest.java | 12 +- .../org/apache/qpid/server/queue/MockAMQQueue.java | 78 +- .../qpid/server/queue/MockMessageInstance.java | 210 +++ .../apache/qpid/server/queue/MockQueueEntry.java | 242 ---- .../qpid/server/queue/PriorityQueueListTest.java | 17 +- .../qpid/server/queue/PriorityQueueTest.java | 119 ++ .../qpid/server/queue/QueueEntryImplTestBase.java | 19 +- .../qpid/server/queue/QueueEntryListTestBase.java | 50 +- .../queue/SelfValidatingSortedQueueEntryList.java | 22 +- .../qpid/server/queue/SimpleAMQQueueTest.java | 1343 ------------------- .../qpid/server/queue/SimpleAMQQueueTestBase.java | 1184 +++++++++++++++++ .../server/queue/SimpleQueueEntryImplTest.java | 21 +- .../server/queue/SimpleQueueEntryListTest.java | 258 ---- .../server/queue/SortedQueueEntryImplTest.java | 99 -- .../server/queue/SortedQueueEntryListTest.java | 71 +- .../qpid/server/queue/SortedQueueEntryTest.java | 119 ++ .../server/queue/StandardQueueEntryListTest.java | 276 ++++ .../qpid/server/queue/StandardQueueTest.java | 363 +++++ .../qpid/server/txn/AutoCommitTransactionTest.java | 8 +- .../qpid/server/txn/LocalTransactionTest.java | 8 +- .../apache/qpid/server/util/BrokerTestHelper.java | 6 +- .../v0_10/MessageConverter_Internal_to_v0_10.java | 156 +++ .../protocol/v0_10/MessageConverter_v0_10.java | 84 ++ .../v0_10/MessageConverter_v0_10_to_Internal.java | 271 ++++ .../qpid/server/protocol/v0_10/ServerSession.java | 4 +- .../org.apache.qpid.server.plugin.MessageConverter | 2 + .../qpid/server/protocol/v0_8/AMQChannel.java | 8 +- .../v0_8/MessageConverter_Internal_to_v0_8.java | 268 ++++ .../v0_8/MessageConverter_v0_8_to_Internal.java | 148 +++ .../org.apache.qpid.server.plugin.MessageConverter | 20 + .../qpid/server/protocol/v0_8/AcknowledgeTest.java | 6 +- .../protocol/v0_8/QueueBrowserUsesNoAckTest.java | 6 +- .../v1_0/MessageConverter_Internal_to_v1_0.java | 140 ++ .../protocol/v1_0/MessageConverter_to_1_0.java | 151 ++- .../v1_0/MessageConverter_v1_0_to_Internal.java | 281 ++++ .../qpid/server/protocol/v1_0/SendingLink_1_0.java | 27 +- .../org.apache.qpid.server.plugin.MessageConverter | 20 + .../v0_8_v0_10/MessageConverter_0_10_to_0_8.java | 2 +- qpid/java/broker-plugins/management-amqp/build.xml | 32 + qpid/java/broker-plugins/management-amqp/pom.xml | 48 + .../server/management/amqp/ManagedEntityType.java | 73 + .../server/management/amqp/ManagementNode.java | 1402 ++++++++++++++++++++ .../management/amqp/ManagementNodeConsumer.java | 242 ++++ .../management/amqp/ManagementNodeCreator.java | 39 + .../server/management/amqp/ManagementResponse.java | 220 +++ ...org.apache.qpid.server.plugin.SystemNodeCreator | 19 + .../plugin/servlet/rest/MessageContentServlet.java | 3 - .../src/main/java/resources/addQueue.html | 8 +- .../java/resources/js/qpid/management/Queue.js | 8 +- .../java/resources/js/qpid/management/addQueue.js | 4 +- .../src/main/java/resources/showQueue.html | 2 +- .../apache/qpid/server/jmx/mbeans/QueueMBean.java | 2 +- .../qpid/server/jmx/mbeans/QueueMBeanTest.java | 2 +- qpid/java/build.deps | 1 + .../unit/basic/FieldTableKeyEnumeratorTest.java | 2 +- .../qpid/framing/BasicContentHeaderProperties.java | 4 +- qpid/java/ivy.nexus.xml | 6 + qpid/java/pom.xml | 1 + .../apache/qpid/server/store/MessageStoreTest.java | 11 +- .../management/jmx/QueueManagementTest.java | 6 +- .../java/org/apache/qpid/systest/rest/Asserts.java | 2 +- .../qpid/systest/rest/VirtualHostRestTest.java | 3 +- 147 files changed, 8337 insertions(+), 3439 deletions(-) create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageHeader.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaData.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AmqpManagement.java delete mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueue.java delete mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntry.java delete mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueue.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntry.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntryList.java create mode 100644 qpid/java/broker-core/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageMetaDataType delete mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java delete mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java delete mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTestBase.java delete mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java delete mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java create mode 100644 qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_Internal_to_v0_10.java create mode 100644 qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10_to_Internal.java create mode 100644 qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_Internal_to_v0_8.java create mode 100644 qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java create mode 100644 qpid/java/broker-plugins/amqp-0-8-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter create mode 100644 qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_Internal_to_v1_0.java create mode 100644 qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_v1_0_to_Internal.java create mode 100644 qpid/java/broker-plugins/amqp-1-0-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter create mode 100644 qpid/java/broker-plugins/management-amqp/build.xml create mode 100644 qpid/java/broker-plugins/management-amqp/pom.xml create mode 100644 qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagedEntityType.java create mode 100644 qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java create mode 100644 qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java create mode 100644 qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeCreator.java create mode 100644 qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java create mode 100644 qpid/java/broker-plugins/management-amqp/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.SystemNodeCreator diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/DestinationImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/DestinationImpl.java index 924c5b9857..9f39d2c94f 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/DestinationImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/DestinationImpl.java @@ -24,6 +24,7 @@ import org.apache.qpid.amqp_1_0.jms.Queue; import org.apache.qpid.amqp_1_0.jms.Topic; import javax.jms.JMSException; +import java.util.UUID; import java.util.WeakHashMap; public class DestinationImpl implements Destination, Queue, Topic @@ -32,6 +33,7 @@ public class DestinationImpl implements Destination, Queue, Topic new WeakHashMap(); private final String _address; + private String _localTerminus; protected DestinationImpl(String address) { @@ -62,13 +64,24 @@ public class DestinationImpl implements Destination, Queue, Topic && _address.equals(((DestinationImpl)obj)._address); } - public static synchronized DestinationImpl createDestination(final String address) + public static synchronized DestinationImpl createDestination(String address) { - DestinationImpl destination = DESTINATION_CACHE.get(address); - if(destination == null) + DestinationImpl destination; + if (address.endsWith("!!")) { + address = address.substring(0, address.length() - 2); + String localTerminusName = UUID.randomUUID().toString(); destination = new DestinationImpl(address); - DESTINATION_CACHE.put(address, destination); + destination.setLocalTerminus(localTerminusName); + } + else + { + destination = DESTINATION_CACHE.get(address); + if (destination == null) + { + destination = new DestinationImpl(address); + DESTINATION_CACHE.put(address, destination); + } } return destination; } @@ -82,4 +95,14 @@ public class DestinationImpl implements Destination, Queue, Topic { return getAddress(); } + + void setLocalTerminus(final String localTerminus) + { + _localTerminus = localTerminus; + } + + String getLocalTerminus() + { + return _localTerminus; + } } diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageConsumerImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageConsumerImpl.java index 96ee1e984d..d7bb546d7a 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageConsumerImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageConsumerImpl.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import javax.jms.Destination; import javax.jms.ExceptionListener; import javax.jms.IllegalStateException; @@ -159,7 +160,8 @@ public class MessageConsumerImpl implements MessageConsumer, QueueReceiver, Topi { try { - return _session.getClientSession().createReceiver(_session.toAddress(_destination), AcknowledgeMode.ALO, + String targetAddr = _destination.getLocalTerminus() != null ? _destination.getLocalTerminus() : UUID.randomUUID().toString(); + return _session.getClientSession().createReceiver(_session.toAddress(_destination), targetAddr, AcknowledgeMode.ALO, _linkName, _durable, getFilters(), null); } catch (ConnectionErrorException e) diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageImpl.java index fed9b5904f..f2d0cb5b18 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageImpl.java @@ -75,6 +75,7 @@ public abstract class MessageImpl implements Message private boolean _isFromQueue; private boolean _isFromTopic; private long _expiration; + private DestinationImpl _replyTo; protected MessageImpl(Header header, MessageAnnotations messageAnnotations, @@ -182,11 +183,12 @@ public abstract class MessageImpl implements Message public DestinationImpl getJMSReplyTo() throws JMSException { - return toDestination(getReplyTo(), splitCommaSeparateSet((String) getMessageAnnotation(REPLY_TO_TYPE))); + return _replyTo != null ? _replyTo : toDestination(getReplyTo(), splitCommaSeparateSet((String) getMessageAnnotation(REPLY_TO_TYPE))); } public void setJMSReplyTo(Destination destination) throws NonAMQPDestinationException { + _replyTo = (DestinationImpl) destination; if( destination==null ) { setReplyTo(null); @@ -194,9 +196,16 @@ public abstract class MessageImpl implements Message } else { - DecodedDestination dd = toDecodedDestination(destination); - setReplyTo(dd.getAddress()); - messageAnnotationMap().put(REPLY_TO_TYPE, join(",", dd.getAttributes())); + if(_replyTo.getLocalTerminus() != null) + { + setReplyTo(_replyTo.getLocalTerminus()); + } + else + { + DecodedDestination dd = toDecodedDestination(destination); + setReplyTo(dd.getAddress()); + messageAnnotationMap().put(REPLY_TO_TYPE, join(",", dd.getAttributes())); + } } } diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageProducerImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageProducerImpl.java index e459575974..b12540d597 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageProducerImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageProducerImpl.java @@ -77,7 +77,11 @@ public class MessageProducerImpl implements MessageProducer, QueueSender, TopicP { try { - _sender = _session.getClientSession().createSender(_session.toAddress(_destination), new Session.SourceConfigurator() + final String sourceName = _destination.getLocalTerminus() != null + ? _destination.getLocalTerminus() + : UUID.randomUUID().toString(); + + _sender = _session.getClientSession().createSender(sourceName, _session.toAddress(_destination), new Session.SourceConfigurator() { public void configureSource(final Source source) { diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueImpl.java index cb56843a72..589ee5204f 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueImpl.java @@ -20,6 +20,7 @@ package org.apache.qpid.amqp_1_0.jms.impl; import org.apache.qpid.amqp_1_0.jms.Queue; +import java.util.UUID; import java.util.WeakHashMap; public class QueueImpl extends DestinationImpl implements Queue @@ -37,13 +38,24 @@ public class QueueImpl extends DestinationImpl implements Queue return getAddress(); } - public static synchronized QueueImpl createQueue(final String address) + public static synchronized QueueImpl createQueue(String address) { - QueueImpl queue = QUEUE_CACHE.get(address); - if(queue == null) + QueueImpl queue; + if (address.endsWith("!!")) { + address = address.substring(0, address.length() - 2); + String localTerminusName = UUID.randomUUID().toString(); queue = new QueueImpl(address); - QUEUE_CACHE.put(address, queue); + queue.setLocalTerminus(localTerminusName); + } + else + { + queue = QUEUE_CACHE.get(address); + if(queue == null) + { + queue = new QueueImpl(address); + QUEUE_CACHE.put(address, queue); + } } return queue; } diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueReceiverImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueReceiverImpl.java index 4e9e9d6a39..21161ff83f 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueReceiverImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/QueueReceiverImpl.java @@ -24,6 +24,8 @@ import org.apache.qpid.amqp_1_0.client.Receiver; import org.apache.qpid.amqp_1_0.jms.Queue; import org.apache.qpid.amqp_1_0.jms.QueueReceiver; +import java.util.UUID; + public class QueueReceiverImpl extends MessageConsumerImpl implements QueueReceiver { QueueReceiverImpl(final QueueImpl destination, @@ -40,7 +42,11 @@ public class QueueReceiverImpl extends MessageConsumerImpl implements QueueRecei { try { - return getSession().getClientSession().createMovingReceiver(getSession().toAddress(getDestination())); + final String targetAddr = + getDestination().getLocalTerminus() != null ? getDestination().getLocalTerminus() : UUID + .randomUUID().toString(); + return getSession().getClientSession().createMovingReceiver(getSession().toAddress(getDestination()), + targetAddr); } catch (ConnectionErrorException e) { diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/SessionImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/SessionImpl.java index 2318b8ba9b..bd67ff681a 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/SessionImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/SessionImpl.java @@ -460,7 +460,7 @@ public class SessionImpl implements Session, QueueSession, TopicSession { checkClosed(); checkNotTopicSession(); - return new QueueImpl(s); + return QueueImpl.valueOf(s); } public QueueReceiver createReceiver(final Queue queue) throws JMSException @@ -488,7 +488,7 @@ public class SessionImpl implements Session, QueueSession, TopicSession { checkClosed(); checkNotQueueSession(); - return new TopicImpl(s); + return TopicImpl.valueOf(s); } public TopicSubscriber createSubscriber(final Topic topic) throws JMSException diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicImpl.java index 5292944075..edc583e233 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicImpl.java @@ -20,6 +20,7 @@ package org.apache.qpid.amqp_1_0.jms.impl; import org.apache.qpid.amqp_1_0.jms.Topic; +import java.util.UUID; import java.util.WeakHashMap; public class TopicImpl extends DestinationImpl implements Topic @@ -38,13 +39,24 @@ public class TopicImpl extends DestinationImpl implements Topic return getAddress(); } - public static synchronized TopicImpl createTopic(final String address) + public static synchronized TopicImpl createTopic(String address) { - TopicImpl topic = TOPIC_CACHE.get(address); - if(topic == null) + TopicImpl topic; + if (address.endsWith("!!")) { + address = address.substring(0, address.length() - 2); + String localTerminusName = UUID.randomUUID().toString(); topic = new TopicImpl(address); - TOPIC_CACHE.put(address, topic); + topic.setLocalTerminus(localTerminusName); + } + else + { + topic = TOPIC_CACHE.get(address); + if(topic == null) + { + topic = new TopicImpl(address); + TOPIC_CACHE.put(address, topic); + } } return topic; } diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicSubscriberImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicSubscriberImpl.java index 69e07f30a1..b89025a27b 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicSubscriberImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/TopicSubscriberImpl.java @@ -19,6 +19,7 @@ package org.apache.qpid.amqp_1_0.jms.impl; import java.util.Map; +import java.util.UUID; import javax.jms.InvalidSelectorException; import javax.jms.JMSException; import org.apache.qpid.amqp_1_0.client.AcknowledgeMode; @@ -67,7 +68,9 @@ public class TopicSubscriberImpl extends MessageConsumerImpl implements TopicSub try { String address = getSession().toAddress(getDestination()); - Receiver receiver = getSession().getClientSession().createReceiver(address, + String targetAddress = getDestination().getLocalTerminus() != null ? getDestination().getLocalTerminus() : UUID.randomUUID().toString(); + + Receiver receiver = getSession().getClientSession().createReceiver(address, targetAddress, StdDistMode.COPY, AcknowledgeMode.ALO, getLinkName(), isDurable(), getFilters(), null); diff --git a/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Session.java b/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Session.java index cac4775b54..290895df60 100644 --- a/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Session.java +++ b/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Session.java @@ -78,8 +78,14 @@ public class Session public Sender createSender(final String targetName, final SourceConfigurator configurator) throws Sender.SenderCreationException, ConnectionClosedException { - final String sourceName = UUID.randomUUID().toString(); + return createSender(sourceName, targetName, configurator); + } + + public Sender createSender(final String sourceName, final String targetName, final SourceConfigurator configurator) + throws Sender.SenderCreationException, ConnectionClosedException + { + return new Sender(this, targetName +"<-"+sourceName, targetName, sourceName, false) { @Override @@ -150,93 +156,118 @@ public class Session public Receiver createReceiver(final String sourceAddr) throws ConnectionErrorException { - return createReceiver(sourceAddr, null, AcknowledgeMode.ALO); + return createReceiver(sourceAddr, UUID.randomUUID().toString(), null, AcknowledgeMode.ALO); } public Receiver createReceiver(final String queue, final AcknowledgeMode mode) throws ConnectionErrorException { - return createReceiver(queue, null, mode); + return createReceiver(queue, UUID.randomUUID().toString(), null, mode); } public Receiver createReceiver(final String queue, final AcknowledgeMode mode, String linkName) throws ConnectionErrorException { - return createReceiver(queue, null, mode, linkName); + return createReceiver(queue, UUID.randomUUID().toString(), null, mode, linkName); } public Receiver createReceiver(final String queue, final AcknowledgeMode mode, String linkName, boolean isDurable) throws ConnectionErrorException { - return createReceiver(queue, null, mode, linkName, isDurable); + return createReceiver(queue, UUID.randomUUID().toString(), null, mode, linkName, isDurable); } public Receiver createReceiver(final String queue, final AcknowledgeMode mode, String linkName, boolean isDurable, Map filters, Map unsettled) throws ConnectionErrorException { - return createReceiver(queue, null, mode, linkName, isDurable, filters, unsettled); + return createReceiver(queue, (DistributionMode) null, mode, linkName, isDurable, filters, unsettled); } - - public Receiver createReceiver(final String queue, final AcknowledgeMode mode, String linkName, - boolean isDurable, Map unsettled) + public Receiver createReceiver(final String queue, String targetName, final AcknowledgeMode mode, String linkName, boolean isDurable, + Map filters, Map unsettled) throws ConnectionErrorException { - return createReceiver(queue, null, mode, linkName, isDurable, unsettled); + return createReceiver(queue, targetName, null, mode, linkName, isDurable, filters, unsettled); } - private synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode) + public Receiver createReceiver(final String queue, final AcknowledgeMode mode, String linkName, + boolean isDurable, Map unsettled) throws ConnectionErrorException { - return createReceiver(sourceAddr, mode, AcknowledgeMode.ALO); + return createReceiver(queue, UUID.randomUUID().toString(), null, mode, linkName, isDurable, unsettled); } - private synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode, String linkName) + + private synchronized Receiver createReceiver(final String sourceAddr, + final String targetAddr, + DistributionMode mode) throws ConnectionErrorException { - return createReceiver(sourceAddr, mode, AcknowledgeMode.ALO, linkName); + return createReceiver(sourceAddr, targetAddr, mode, AcknowledgeMode.ALO); } - private synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode, - final AcknowledgeMode ackMode) + private synchronized Receiver createReceiver(final String sourceAddr, + final String targetAddr, + DistributionMode mode, + final AcknowledgeMode ackMode) throws ConnectionErrorException { - return createReceiver(sourceAddr, mode, ackMode, null); + return createReceiver(sourceAddr, targetAddr, mode, ackMode, null); } - private synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode, - final AcknowledgeMode ackMode, String linkName) + private synchronized Receiver createReceiver(final String sourceAddr, + final String targetAddr, + DistributionMode mode, + final AcknowledgeMode ackMode, + String linkName) throws ConnectionErrorException { - return createReceiver(sourceAddr,mode, ackMode, linkName, false); + return createReceiver(sourceAddr, targetAddr, mode, ackMode, linkName, false); } - private synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode, - final AcknowledgeMode ackMode, String linkName, boolean isDurable) + private synchronized Receiver createReceiver(final String sourceAddr, + final String targetAddr, + DistributionMode mode, + final AcknowledgeMode ackMode, + String linkName, + boolean isDurable) throws ConnectionErrorException { - return createReceiver(sourceAddr, mode, ackMode, linkName, isDurable, null); + return createReceiver(sourceAddr, targetAddr, mode, ackMode, linkName, isDurable, null); } - private synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode, - final AcknowledgeMode ackMode, String linkName, boolean isDurable, - Map unsettled) + private synchronized Receiver createReceiver(final String sourceAddr, + final String targetAddr, + DistributionMode mode, + final AcknowledgeMode ackMode, + String linkName, + boolean isDurable, + Map unsettled) throws ConnectionErrorException { return createReceiver(sourceAddr,mode,ackMode, linkName, isDurable, null, unsettled); } public synchronized Receiver createReceiver(final String sourceAddr, DistributionMode mode, + final AcknowledgeMode ackMode, String linkName, boolean isDurable, + Map filters, Map unsettled) + throws ConnectionErrorException + { + return createReceiver(sourceAddr, UUID.randomUUID().toString(), mode, ackMode, linkName, isDurable, filters, unsettled); + } + + public synchronized Receiver createReceiver(final String sourceAddr, String targetAddr, DistributionMode mode, final AcknowledgeMode ackMode, String linkName, boolean isDurable, Map filters, Map unsettled) throws ConnectionErrorException { final Target target = new Target(); + target.setAddress(targetAddr); final Source source = new Source(); source.setAddress(sourceAddr); source.setDistributionMode(mode); @@ -258,12 +289,17 @@ public class Session public synchronized Receiver createCopyingReceiver(final String sourceAddr) throws ConnectionErrorException { - return createReceiver(sourceAddr, StdDistMode.COPY); + return createReceiver(sourceAddr, UUID.randomUUID().toString(), StdDistMode.COPY); } public synchronized Receiver createMovingReceiver(final String sourceAddr) throws ConnectionErrorException { - return createReceiver(sourceAddr, StdDistMode.MOVE); + return createReceiver(sourceAddr, UUID.randomUUID().toString(), StdDistMode.MOVE); + } + + public synchronized Receiver createMovingReceiver(final String sourceAddr, final String targetAddr) throws ConnectionErrorException + { + return createReceiver(sourceAddr, UUID.randomUUID().toString(), StdDistMode.MOVE); } public Receiver createTemporaryQueueReceiver() throws AmqpErrorException, ConnectionErrorException diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index bc670bd848..600c60bdb3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -43,6 +43,7 @@ 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.DurableConfigurationStoreHelper; +import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.util.Action; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -428,10 +429,10 @@ public abstract class AbstractExchange implements Exchange return queues; } - public final int send(final ServerMessage message, + public final > int send(final M message, final InstanceProperties instanceProperties, final ServerTransaction txn, - final Action> postEnqueueAction) + final Action> postEnqueueAction) { List queues = route(message, instanceProperties); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultExchange.java index 33c5218b4c..78b9664cd3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultExchange.java @@ -46,6 +46,7 @@ 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.queue.QueueRegistry; +import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.util.Action; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -335,10 +336,10 @@ public class DefaultExchange implements Exchange return _id; } - public final int send(final ServerMessage message, + public final > int send(final M message, final InstanceProperties instanceProperties, final ServerTransaction txn, - final Action> postEnqueueAction) + final Action> postEnqueueAction) { final AMQQueue q = _virtualHost.getQueue(message.getRoutingKey()); if(q == null) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java index 967c629749..62f5b3634b 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.message; import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.util.Action; @@ -37,8 +38,8 @@ public interface MessageDestination extends MessageNode * @param postEnqueueAction action to perform on the result of every enqueue (may be null) * @return the number of queues in which the message was enqueued performed */ - int send(ServerMessage message, + > int send(M message, InstanceProperties instanceProperties, ServerTransaction txn, - Action> postEnqueueAction); + Action> postEnqueueAction); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java index 97cb66cce4..49969ce3c1 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java @@ -30,7 +30,7 @@ import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.util.Action; import org.apache.qpid.server.util.StateChangeListener; -public interface MessageInstance +public interface MessageInstance, C extends Consumer> { @@ -45,9 +45,9 @@ public interface MessageInstance void decrementDeliveryCount(); - void addStateChangeListener(StateChangeListener, State> listener); + void addStateChangeListener(StateChangeListener listener); - boolean removeStateChangeListener(StateChangeListener, State> listener); + boolean removeStateChangeListener(StateChangeListener listener); boolean acquiredByConsumer(); @@ -71,7 +71,7 @@ public interface MessageInstance int getMaximumDeliveryCount(); - int routeToAlternate(Action> action, ServerTransaction txn); + int routeToAlternate(Action> action, ServerTransaction txn); Filterable asFilterable(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java index 06ff76f103..49b0f2995c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java @@ -32,17 +32,17 @@ import org.apache.qpid.server.store.TransactionLogResource; import java.util.Collection; import java.util.EnumSet; -public interface MessageSource extends TransactionLogResource, MessageNode +public interface MessageSource> extends TransactionLogResource, MessageNode { - C addConsumer(ConsumerTarget target, FilterManager filters, + C addConsumer(T target, FilterManager filters, Class messageClass, String consumerName, EnumSet options) throws AMQException; Collection getConsumers(); - void addConsumerRegistrationListener(ConsumerRegistrationListener listener); + void addConsumerRegistrationListener(ConsumerRegistrationListener listener); - void removeConsumerRegistrationListener(ConsumerRegistrationListener listener); + void removeConsumerRegistrationListener(ConsumerRegistrationListener listener); AuthorizationHolder getAuthorizationHolder(); @@ -54,10 +54,10 @@ public interface MessageSource extends TransactionLogResourc boolean isExclusive(); - interface ConsumerRegistrationListener + interface ConsumerRegistrationListener> { - void consumerAdded(AMQQueue queue, Consumer consumer); - void consumerRemoved(AMQQueue queue, Consumer consumer); + void consumerAdded(Q source, Consumer consumer); + void consumerRemoved(Q queue, Consumer consumer); } /** diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java new file mode 100644 index 0000000000..f972bd78f6 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java @@ -0,0 +1,254 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message.internal; + +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.AbstractServerMessageImpl; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoreFuture; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.util.ByteBufferInputStream; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class InternalMessage extends AbstractServerMessageImpl +{ + private final Object _messageBody; + private final int _contentSize; + private InternalMessageHeader _header; + + + InternalMessage(final StoredMessage handle, + final InternalMessageHeader header, + final Object messageBody) + { + super(handle, null); + _header = header; + _messageBody = messageBody; + _contentSize = handle.getMetaData().getContentSize(); + } + + InternalMessage(final StoredMessage msg) + { + super(msg, null); + _contentSize = msg.getMetaData().getContentSize(); + ByteBuffer buf = msg.getContent(0, _contentSize); + + try + { + ObjectInputStream is = new ObjectInputStream(new ByteBufferInputStream(buf)); + _messageBody = is.readObject(); + + } + catch (IOException e) + { + throw new RuntimeException(e); + } + catch (ClassNotFoundException e) + { + throw new RuntimeException(e); + } + } + + @Override + public String getRoutingKey() + { + return null; + } + + @Override + public InternalMessageHeader getMessageHeader() + { + return _header; + } + + @Override + public long getSize() + { + return _contentSize; + } + + @Override + public long getExpiration() + { + return _header.getExpiration(); + } + + @Override + public long getArrivalTime() + { + return _header.getArrivalTime(); + } + + public Object getMessageBody() + { + return _messageBody; + } + + private static InternalMessage createMessage(final MessageStore store, + final AMQMessageHeader header, + final Serializable bodyObject, final boolean persistent) + { + InternalMessageHeader internalHeader; + if(header instanceof InternalMessageHeader) + { + internalHeader = (InternalMessageHeader) header; + } + else + { + internalHeader = new InternalMessageHeader(header); + } + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + try + { + ObjectOutputStream os = new ObjectOutputStream(bytesOut); + os.writeObject(bodyObject); + byte[] bytes = bytesOut.toByteArray(); + + + final InternalMessageMetaData metaData = InternalMessageMetaData.create(persistent, internalHeader, bytes.length); + StoredMessage handle = + store.addMessage(metaData); + handle.addContent(0, ByteBuffer.wrap(bytes)); + + return new InternalMessage(handle, internalHeader, bodyObject); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public static InternalMessage createStringMessage(MessageStore store, AMQMessageHeader header, String messageBody) + { + return createMessage(store, header, messageBody, false); + } + + public static InternalMessage createMapMessage(MessageStore store, AMQMessageHeader header, Map messageBody) + { + return createMessage(store, header, new LinkedHashMap(messageBody), false); + } + + public static InternalMessage createListMessage(MessageStore store, AMQMessageHeader header, List messageBody) + { + return createMessage(store, header, new ArrayList(messageBody), false); + } + + public static InternalMessage createBytesMessage(MessageStore store, AMQMessageHeader header, byte[] messageBody) + { + return createMessage(store, header, messageBody, false); + } + + public static InternalMessage convert(long messageNumber, boolean persistent, AMQMessageHeader header, Object messageBody) + { + InternalMessageHeader convertedHeader = new InternalMessageHeader(header); + StoredMessage handle = createReadOnlyHandle(messageNumber, persistent, convertedHeader, messageBody); + return new InternalMessage(handle, convertedHeader, messageBody); + } + + private static StoredMessage createReadOnlyHandle(final long messageNumber, + final boolean persistent, + final InternalMessageHeader header, + final Object messageBody) + { + + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + try + { + ObjectOutputStream os = new ObjectOutputStream(bytesOut); + os.writeObject(messageBody); + final byte[] bytes = bytesOut.toByteArray(); + + + final InternalMessageMetaData metaData = InternalMessageMetaData.create(persistent, header, bytes.length); + + + return new StoredMessage() + { + @Override + public InternalMessageMetaData getMetaData() + { + return metaData; + } + + @Override + public long getMessageNumber() + { + return messageNumber; + } + + @Override + public void addContent(final int offsetInMessage, final ByteBuffer src) + { + throw new UnsupportedOperationException(); + } + + @Override + public int getContent(final int offsetInMessage, final ByteBuffer dst) + { + ByteBuffer buffer = ByteBuffer.wrap(bytes); + buffer.position(offsetInMessage); + buffer = buffer.slice(); + if(dst.remaining() < buffer.remaining()) + { + buffer.limit(dst.remaining()); + } + int pos = dst.position(); + dst.put(buffer); + return dst.position()-pos; + } + + @Override + public ByteBuffer getContent(final int offsetInMessage, final int size) + { + return ByteBuffer.wrap(bytes,offsetInMessage,size); + } + + @Override + public StoreFuture flushToStore() + { + throw new UnsupportedOperationException(); + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageHeader.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageHeader.java new file mode 100644 index 0000000000..75c5a414f4 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageHeader.java @@ -0,0 +1,197 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message.internal; + +import org.apache.qpid.server.message.AMQMessageHeader; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public final class InternalMessageHeader implements AMQMessageHeader, Serializable +{ + private static final long serialVersionUID = 7219183903302678948L; + + private final LinkedHashMap _headers; + private final String _correlationId; + private final long _expiration; + private final String _userId; + private final String _appId; + private final String _messageId; + private final String _mimeType; + private final String _encoding; + private final byte _priority; + private final long _timestamp; + private final String _type; + private final String _replyTo; + private long _arrivalTime; + + public InternalMessageHeader(final Map headers, + final String correlationId, + final long expiration, + final String userId, + final String appId, + final String messageId, + final String mimeType, + final String encoding, + final byte priority, final long timestamp, final String type, final String replyTo) + { + _headers = headers == null ? new LinkedHashMap() + : new LinkedHashMap(headers); + + _correlationId = correlationId; + _expiration = expiration; + _userId = userId; + _appId = appId; + _messageId = messageId; + _mimeType = mimeType; + _encoding = encoding; + _priority = priority; + _timestamp = timestamp; + _type = type; + _replyTo = replyTo; + _arrivalTime = System.currentTimeMillis(); + } + + public InternalMessageHeader(final AMQMessageHeader header) + { + _correlationId = header.getCorrelationId(); + _expiration = header.getExpiration(); + _userId = header.getUserId(); + _appId = header.getAppId(); + _messageId = header.getMessageId(); + _mimeType = header.getMimeType(); + _encoding = header.getEncoding(); + _priority = header.getPriority(); + _timestamp = header.getTimestamp(); + _type = header.getType(); + _replyTo = header.getReplyTo(); + _headers = new LinkedHashMap(); + for(String headerName : header.getHeaderNames()) + { + _headers.put(headerName, header.getHeader(headerName)); + } + _arrivalTime = System.currentTimeMillis(); + } + + @Override + public String getCorrelationId() + { + return _correlationId; + } + + @Override + public long getExpiration() + { + return _expiration; + } + + @Override + public String getUserId() + { + return _userId; + } + + @Override + public String getAppId() + { + return _appId; + } + + @Override + public String getMessageId() + { + return _messageId; + } + + @Override + public String getMimeType() + { + return _mimeType; + } + + @Override + public String getEncoding() + { + return _encoding; + } + + @Override + public byte getPriority() + { + return _priority; + } + + @Override + public long getTimestamp() + { + return _timestamp; + } + + @Override + public String getType() + { + return _type; + } + + @Override + public String getReplyTo() + { + return _replyTo; + } + + @Override + public Object getHeader(final String name) + { + return _headers.get(name); + } + + @Override + public boolean containsHeaders(final Set names) + { + return _headers.keySet().containsAll(names); + } + + @Override + public boolean containsHeader(final String name) + { + return _headers.keySet().contains(name); + } + + @Override + public Collection getHeaderNames() + { + return Collections.unmodifiableCollection(_headers.keySet()); + } + + long getArrivalTime() + { + return _arrivalTime; + } + + public Map getHeaderMap() + { + return Collections.unmodifiableMap(new LinkedHashMap(_headers)); + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaData.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaData.java new file mode 100644 index 0000000000..d7772657a2 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaData.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.message.internal; + +import org.apache.qpid.server.store.StorableMessageMetaData; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.nio.ByteBuffer; + +public class InternalMessageMetaData implements StorableMessageMetaData +{ + + + private boolean _isPersistent; + private byte[] _headerBytes; + private int _contentSize; + + public InternalMessageMetaData(final boolean isPersistent, final byte[] headerBytes, final int contentSize) + { + _isPersistent = isPersistent; + _headerBytes = headerBytes; + _contentSize = contentSize; + } + + @Override + public InternalMessageMetaDataType getType() + { + return InternalMessageMetaDataType.INSTANCE; + } + + @Override + public int getStorableSize() + { + return _headerBytes.length; + } + + @Override + public int writeToBuffer(final ByteBuffer dest) + { + dest.put(_headerBytes); + return _headerBytes.length; + } + + @Override + public int getContentSize() + { + return _contentSize; + } + + @Override + public boolean isPersistent() + { + return _isPersistent; + } + + static InternalMessageMetaData create(boolean persistent, final InternalMessageHeader header, int contentSize) + { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + try + { + ObjectOutputStream os = new ObjectOutputStream(bytesOut); + os.writeObject(header); + byte[] bytes = bytesOut.toByteArray(); + + return new InternalMessageMetaData(persistent, bytes, contentSize); + + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java new file mode 100644 index 0000000000..eb90599aef --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.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.message.internal; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.plugin.MessageMetaDataType; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.util.ByteBufferInputStream; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.nio.ByteBuffer; + +public class InternalMessageMetaDataType implements MessageMetaDataType +{ + public static final int INTERNAL_ORDINAL = 999; + public static final String TYPE = "INTERNAL"; + + @Override + public int ordinal() + { + return INTERNAL_ORDINAL; + } + + @Override + public InternalMessageMetaData createMetaData(final ByteBuffer buf) + { + try + { + ObjectInputStream is = new ObjectInputStream(new ByteBufferInputStream(buf)); + InternalMessageMetaData metaData = (InternalMessageMetaData) is.readObject(); + return metaData; + } + catch (IOException e) + { + throw new RuntimeException("Cannot decode message header"); + } + catch (ClassNotFoundException e) + { + throw new RuntimeException(e); + } + + } + + @Override + public ServerMessage createMessage(final StoredMessage msg) + { + return new InternalMessage(msg); + } + + @Override + public String getType() + { + return TYPE; + } + + public static final InternalMessageMetaDataType INSTANCE = new InternalMessageMetaDataType(); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AccessControlProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AccessControlProvider.java index d96bef0463..20d0166c9d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AccessControlProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AccessControlProvider.java @@ -27,9 +27,7 @@ import org.apache.qpid.server.security.AccessControl; public interface AccessControlProvider extends ConfiguredObject { - public static final String ID = "id"; public static final String DESCRIPTION = "description"; - public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; public static final String LIFETIME_POLICY = "lifetimePolicy"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AmqpManagement.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AmqpManagement.java new file mode 100644 index 0000000000..43b77bfe1d --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AmqpManagement.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.model; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface AmqpManagement +{ + String[] attributes(); + String[] operations(); + boolean managesChildren() default false; // for objects that manage children, a management node needs to be created + boolean creatable() default true; + String defaultImplementation() default ""; // in this case the class/interface itself is to be used +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java index f75d0211cb..c111f40cc8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java @@ -29,9 +29,7 @@ import org.apache.qpid.server.security.SubjectCreator; public interface AuthenticationProvider extends ConfiguredObject { - public static final String ID = "id"; public static final String DESCRIPTION = "description"; - public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; public static final String LIFETIME_POLICY = "lifetimePolicy"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Binding.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Binding.java index fdb009386c..d5f833e393 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Binding.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Binding.java @@ -43,9 +43,7 @@ public interface Binding extends ConfiguredObject public String ARGUMENTS = "arguments"; public String CREATED = "created"; public String DURABLE = "durable"; - public String ID = "id"; public String LIFETIME_POLICY = "lifetimePolicy"; - public String NAME = "name"; public String STATE = "state"; public String TIME_TO_LIVE = "timeToLive"; public String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java index 0c1a6de58b..5df6d9475e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java @@ -48,9 +48,7 @@ public interface Broker extends ConfiguredObject String SUPPORTED_PREFERENCES_PROVIDERS_TYPES = "supportedPreferencesProviderTypes"; String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java index 6762e3dd93..ab9c60573a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java @@ -25,12 +25,22 @@ import java.util.Collection; import java.util.Map; import java.util.UUID; +@AmqpManagement( + attributes = { + ConfiguredObject.ID, + ConfiguredObject.NAME + }, + operations = {}, + creatable = false +) /** * An object that can be "managed" (eg via the web interface) and usually read from configuration. */ public interface ConfiguredObject { - + public static final String ID = "id"; + public static final String NAME = "name"; +// public static final String TYPE = "type"; /** * Get the universally unique identifier for the object * diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java index 31d40c7c3e..a7350f528c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java @@ -24,6 +24,32 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +@AmqpManagement( + attributes = { + Connection.ID, + Connection.NAME, + Connection.STATE, + Connection.DURABLE, + Connection.LIFETIME_POLICY, + Connection.TIME_TO_LIVE, + Connection.CREATED, + Connection.UPDATED, + Connection.CLIENT_ID, + Connection.CLIENT_VERSION, + Connection.INCOMING, + Connection.LOCAL_ADDRESS, + Connection.PRINCIPAL, + Connection.PROPERTIES, + Connection.REMOTE_ADDRESS, + Connection.REMOTE_PROCESS_NAME, + Connection.REMOTE_PROCESS_PID, + Connection.SESSION_COUNT_LIMIT, + Connection.TRANSPORT, + Connection.PORT + }, + operations = {}, + creatable = false +) public interface Connection extends ConfiguredObject { @@ -59,8 +85,6 @@ public interface Connection extends ConfiguredObject // Attributes - public static final String ID = "id"; - public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; public static final String LIFETIME_POLICY = "lifetimePolicy"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java index 958177e713..6f8726d0c8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java @@ -33,9 +33,7 @@ public interface Consumer extends ConfiguredObject public String SETTLEMENT_MODE = "settlementMode"; public String CREATED = "created"; public String DURABLE = "durable"; - public String ID = "id"; public String LIFETIME_POLICY = "lifetimePolicy"; - public String NAME = "name"; public String STATE = "state"; public String TIME_TO_LIVE = "timeToLive"; public String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java index e63c71e955..c4575a7359 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java @@ -25,6 +25,22 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +@AmqpManagement( + attributes = { + Exchange.ID, + Exchange.NAME, + Exchange.STATE, + Exchange.DURABLE, + Exchange.LIFETIME_POLICY, + Exchange.TIME_TO_LIVE, + Exchange.CREATED, + Exchange.UPDATED, + Exchange.ALTERNATE_EXCHANGE, + Exchange.TYPE + }, + operations = {} +) + public interface Exchange extends ConfiguredObject { String BINDING_COUNT = "bindingCount"; @@ -47,9 +63,7 @@ public interface Exchange extends ConfiguredObject String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Group.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Group.java index aacd515107..e62949708d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Group.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Group.java @@ -27,9 +27,7 @@ public interface Group extends ConfiguredObject { String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupMember.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupMember.java index 6832cc6fa6..46dd6ec3e2 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupMember.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupMember.java @@ -27,9 +27,7 @@ public interface GroupMember extends ConfiguredObject { String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupProvider.java index 9016f97927..e5c64ec882 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/GroupProvider.java @@ -27,9 +27,7 @@ import java.util.Set; public interface GroupProvider extends ConfiguredObject { - public static final String ID = "id"; public static final String DESCRIPTION = "description"; - public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; public static final String LIFETIME_POLICY = "lifetimePolicy"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java index ab909390bd..1e1cbb7cef 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java @@ -28,8 +28,6 @@ import javax.net.ssl.KeyManager; public interface KeyStore extends ConfiguredObject { - String ID = "id"; - String NAME = "name"; String DURABLE = "durable"; String LIFETIME_POLICY = "lifetimePolicy"; String STATE = "state"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Plugin.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Plugin.java index b9503a5841..7cdea9d12c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Plugin.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Plugin.java @@ -29,9 +29,7 @@ public interface Plugin extends ConfiguredObject //Hack, using it for the class name only for consistency with the other things. String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java index 60d62e3f27..9458ac4120 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java @@ -29,9 +29,7 @@ public interface Port extends ConfiguredObject { String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/PreferencesProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/PreferencesProvider.java index fadd036a58..c895ce36f8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/PreferencesProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/PreferencesProvider.java @@ -29,8 +29,6 @@ import java.util.Set; public interface PreferencesProvider extends ConfiguredObject { - String ID = "id"; - String NAME = "name"; String TYPE = "type"; String CREATED = "created"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java index ae2031bd71..dc65c6ef81 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java @@ -25,6 +25,40 @@ import java.util.Collection; import java.util.Collections; import org.apache.qpid.server.queue.QueueEntryVisitor; +@AmqpManagement( + attributes = { + Queue.ID, + Queue.NAME, + Queue.DESCRIPTION, + Queue.STATE, + Queue.DURABLE, + Queue.LIFETIME_POLICY, + Queue.TIME_TO_LIVE, + Queue.CREATED, + Queue.UPDATED, + Queue.QUEUE_TYPE, + Queue.ALTERNATE_EXCHANGE, + Queue.EXCLUSIVE, + Queue.OWNER, + Queue.NO_LOCAL, + Queue.LVQ_KEY, + Queue.SORT_KEY, + Queue.MESSAGE_GROUP_KEY, + Queue.MESSAGE_GROUP_SHARED_GROUPS, + Queue.MAXIMUM_DELIVERY_ATTEMPTS, + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, + Queue.QUEUE_FLOW_STOPPED, + Queue.ALERT_THRESHOLD_MESSAGE_AGE, + Queue.ALERT_THRESHOLD_MESSAGE_SIZE, + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, + Queue.ALERT_REPEAT_GAP, + Queue.PRIORITIES + }, + operations = {} +) + public interface Queue extends ConfiguredObject { public static final String BINDING_COUNT = "bindingCount"; @@ -69,9 +103,7 @@ public interface Queue extends ConfiguredObject - public static final String ID = "id"; public static final String DESCRIPTION = "description"; - public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; public static final String LIFETIME_POLICY = "lifetimePolicy"; @@ -98,7 +130,7 @@ public interface Queue extends ConfiguredObject public static final String QUEUE_FLOW_RESUME_SIZE_BYTES = "queueFlowResumeSizeBytes"; public static final String QUEUE_FLOW_STOPPED = "queueFlowStopped"; public static final String SORT_KEY = "sortKey"; - public static final String TYPE = "type"; + public static final String QUEUE_TYPE = "queueType"; public static final String PRIORITIES = "priorities"; public static final String CREATE_DLQ_ON_CREATION = "x-qpid-dlq-enabled"; // TODO - this value should change @@ -118,7 +150,7 @@ public interface Queue extends ConfiguredObject TIME_TO_LIVE, CREATED, UPDATED, - TYPE, + QUEUE_TYPE, ALTERNATE_EXCHANGE, EXCLUSIVE, OWNER, diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Session.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Session.java index 355a1cf3b1..40ff3ef686 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Session.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Session.java @@ -51,8 +51,6 @@ public interface Session extends ConfiguredObject XA_TRANSACTION_BRANCH_SUSPENDS)); - public static final String ID = "id"; - public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; public static final String LIFETIME_POLICY = "lifetimePolicy"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/TrustStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/TrustStore.java index d313e1832f..e4eac98bc0 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/TrustStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/TrustStore.java @@ -28,8 +28,6 @@ import javax.net.ssl.TrustManager; public interface TrustStore extends ConfiguredObject { - String ID = "id"; - String NAME = "name"; String DURABLE = "durable"; String LIFETIME_POLICY = "lifetimePolicy"; String STATE = "state"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/User.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/User.java index cf1a688634..9d7dd7c0cd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/User.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/User.java @@ -30,9 +30,7 @@ public interface User extends ConfiguredObject { String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String UPDATED = "updated"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java index 2b5176aa65..f0241f8b30 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java @@ -31,6 +31,43 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +@AmqpManagement( + attributes = { + VirtualHost.ID, + VirtualHost.NAME, + VirtualHost.TYPE, + VirtualHost.STATE, + VirtualHost.DURABLE, + VirtualHost.LIFETIME_POLICY, + VirtualHost.TIME_TO_LIVE, + VirtualHost.CREATED, + VirtualHost.UPDATED, + VirtualHost.SUPPORTED_EXCHANGE_TYPES, + VirtualHost.SUPPORTED_QUEUE_TYPES, + VirtualHost.QUEUE_DEAD_LETTER_QUEUE_ENABLED, + VirtualHost.HOUSEKEEPING_CHECK_PERIOD, + VirtualHost.QUEUE_MAXIMUM_DELIVERY_ATTEMPTS, + VirtualHost.QUEUE_FLOW_CONTROL_SIZE_BYTES, + VirtualHost.QUEUE_FLOW_RESUME_SIZE_BYTES, + VirtualHost.CONFIG_STORE_TYPE, + VirtualHost.CONFIG_STORE_PATH, + VirtualHost.STORE_TYPE, + VirtualHost.STORE_PATH, + VirtualHost.STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, + VirtualHost.STORE_TRANSACTION_IDLE_TIMEOUT_WARN, + VirtualHost.STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE, + VirtualHost.STORE_TRANSACTION_OPEN_TIMEOUT_WARN, + VirtualHost.QUEUE_ALERT_REPEAT_GAP, + VirtualHost.QUEUE_ALERT_THRESHOLD_MESSAGE_AGE, + VirtualHost.QUEUE_ALERT_THRESHOLD_MESSAGE_SIZE, + VirtualHost.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, + VirtualHost.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, + VirtualHost.CONFIG_PATH + }, + operations = {}, + managesChildren = true +) + public interface VirtualHost extends ConfiguredObject { // Statistics @@ -81,9 +118,7 @@ public interface VirtualHost extends ConfiguredObject String SUPPORTED_QUEUE_TYPES = "supportedQueueTypes"; String CREATED = "created"; String DURABLE = "durable"; - String ID = "id"; String LIFETIME_POLICY = "lifetimePolicy"; - String NAME = "name"; String STATE = "state"; String TIME_TO_LIVE = "timeToLive"; String TYPE = "type"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java index d59b13902b..e2c29ede51 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java @@ -26,13 +26,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import org.apache.qpid.AMQException; import org.apache.qpid.AMQStoreException; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.message.MessageSource; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.ConfiguredObjectFinder; import org.apache.qpid.server.model.Exchange; @@ -49,8 +49,9 @@ import org.apache.qpid.server.store.DurableConfigurationStoreHelper; import org.apache.qpid.server.consumer.Consumer; import org.apache.qpid.server.util.MapValueConverter; -final class QueueAdapter extends AbstractAdapter implements Queue, - AMQQueue.ConsumerRegistrationListener, AMQQueue.NotificationListener +final class QueueAdapter> extends AbstractAdapter implements Queue, + MessageSource.ConsumerRegistrationListener, + AMQQueue.NotificationListener { @SuppressWarnings("serial") static final Map ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap(){{ @@ -66,10 +67,11 @@ final class QueueAdapter extends AbstractAdapter implements Queue, put(DESCRIPTION, String.class); }}); - private final AMQQueue _queue; + private final AMQQueue _queue; + private final Map _bindingAdapters = new HashMap(); - private Map _consumerAdapters = + private final Map _consumerAdapters = new HashMap(); @@ -77,7 +79,7 @@ final class QueueAdapter extends AbstractAdapter implements Queue, private QueueStatisticsAdapter _statistics; private QueueNotificationListener _queueNotificationListener; - public QueueAdapter(final VirtualHostAdapter virtualHostAdapter, final AMQQueue queue) + public QueueAdapter(final VirtualHostAdapter virtualHostAdapter, final AMQQueue queue) { super(queue.getId(), virtualHostAdapter.getTaskExecutor()); _vhost = virtualHostAdapter; @@ -124,11 +126,10 @@ final class QueueAdapter extends AbstractAdapter implements Queue, private void populateConsumers() { - Collection actualConsumers = _queue.getConsumers(); + Collection actualConsumers = _queue.getConsumers(); synchronized (_consumerAdapters) { - Iterator iter = _consumerAdapters.keySet().iterator(); for(Consumer consumer : actualConsumers) { if(!_consumerAdapters.containsKey(consumer)) @@ -321,7 +322,7 @@ final class QueueAdapter extends AbstractAdapter implements Queue, { // TODO } - else if(TYPE.equals(name)) + else if(QUEUE_TYPE.equals(name)) { // TODO } @@ -396,9 +397,10 @@ final class QueueAdapter extends AbstractAdapter implements Queue, } else if(LVQ_KEY.equals(name)) { - if(_queue instanceof ConflationQueue) + AMQQueue queue = _queue; + if(queue instanceof ConflationQueue) { - return ((ConflationQueue)_queue).getConflationKey(); + return ((ConflationQueue)queue).getConflationKey(); } } else if(MAXIMUM_DELIVERY_ATTEMPTS.equals(name)) @@ -427,22 +429,24 @@ final class QueueAdapter extends AbstractAdapter implements Queue, } else if(SORT_KEY.equals(name)) { - if(_queue instanceof SortedQueue) + AMQQueue queue = _queue; + if(queue instanceof SortedQueue) { - return ((SortedQueue)_queue).getSortedPropertyName(); + return ((SortedQueue)queue).getSortedPropertyName(); } } - else if(TYPE.equals(name)) + else if(QUEUE_TYPE.equals(name)) { - if(_queue instanceof SortedQueue) + AMQQueue queue = _queue; + if(queue instanceof SortedQueue) { return "sorted"; } - if(_queue instanceof ConflationQueue) + if(queue instanceof ConflationQueue) { return "lvq"; } - if(_queue instanceof AMQPriorityQueue) + if(queue instanceof PriorityQueue) { return "priority"; } @@ -486,9 +490,10 @@ final class QueueAdapter extends AbstractAdapter implements Queue, } else if(PRIORITIES.equals(name)) { - if(_queue instanceof AMQPriorityQueue) + AMQQueue queue = _queue; + if(queue instanceof PriorityQueue) { - return ((AMQPriorityQueue)_queue).getPriorities(); + return ((PriorityQueue)queue).getPriorities(); } } return super.getAttribute(name); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java index f2ce20c74d..c43dc34d2f 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java @@ -66,7 +66,6 @@ import org.apache.qpid.server.plugin.ExchangeType; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; @@ -190,7 +189,10 @@ public final class VirtualHostAdapter extends AbstractAdapter implements Virtual { if(!_exchangeAdapters.containsKey(exchange)) { - _exchangeAdapters.put(exchange, new ExchangeAdapter(this,exchange)); + final ExchangeAdapter adapter = new ExchangeAdapter(this, exchange); + _exchangeAdapters.put(exchange, adapter); + childAdded(adapter); + } } } @@ -208,7 +210,9 @@ public final class VirtualHostAdapter extends AbstractAdapter implements Virtual { if(!_queueAdapters.containsKey(queue)) { - _queueAdapters.put(queue, new QueueAdapter(this, queue)); + final QueueAdapter adapter = new QueueAdapter(this, queue); + _queueAdapters.put(queue, adapter); + childAdded(adapter); } } } @@ -381,9 +385,9 @@ public final class VirtualHostAdapter extends AbstractAdapter implements Virtual { attributes = new HashMap(attributes); - if (attributes.containsKey(Queue.TYPE)) + if (attributes.containsKey(Queue.QUEUE_TYPE)) { - String typeAttribute = MapValueConverter.getStringAttribute(Queue.TYPE, attributes, null); + String typeAttribute = MapValueConverter.getStringAttribute(Queue.QUEUE_TYPE, attributes, null); QueueType queueType = null; try { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemNodeCreator.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemNodeCreator.java index a117524254..5b371c0851 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemNodeCreator.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemNodeCreator.java @@ -31,6 +31,7 @@ public interface SystemNodeCreator extends Pluggable void removeSystemNode(MessageNode node); VirtualHost getVirtualHost(); + org.apache.qpid.server.model.VirtualHost getVirtualHostModel(); } void register(SystemNodeRegistry registry); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java index 75994f6d81..28fadd4162 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java @@ -27,12 +27,11 @@ import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.SimpleAMQQueue; /** * Session model interface. * Extends {@link Comparable} to allow objects to be inserted into a {@link ConcurrentSkipListSet} - * when monitoring the blocking and blocking of queues/sessions in {@link SimpleAMQQueue}. + * when monitoring the blocking and blocking of queues/sessions in {@link AMQQueue}. */ public interface AMQSessionModel extends Comparable { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java deleted file mode 100644 index 46c2a635b7..0000000000 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.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.virtualhost.VirtualHost; - -import java.util.Map; -import java.util.UUID; - -public class AMQPriorityQueue extends OutOfOrderQueue -{ - protected AMQPriorityQueue(UUID id, - final String name, - final boolean durable, - final String owner, - final boolean autoDelete, - boolean exclusive, - final VirtualHost virtualHost, - Map arguments, int priorities) - { - super(id, name, durable, owner, autoDelete, exclusive, virtualHost, new PriorityQueueList.Factory(priorities), arguments); - } - - public int getPriorities() - { - return ((PriorityQueueList) getEntries()).getPriorities(); - } -} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 62927edc29..76477a0a9b 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -37,8 +37,8 @@ import java.util.Collection; import java.util.List; import java.util.Set; -public interface AMQQueue extends Comparable>, ExchangeReferrer, BaseQueue, - MessageSource, CapacityChecker, MessageDestination +public interface AMQQueue, Q extends AMQQueue, C extends Consumer> + extends Comparable, ExchangeReferrer, BaseQueue, MessageSource, CapacityChecker, MessageDestination { public interface NotificationListener @@ -87,41 +87,35 @@ public interface AMQQueue extends Comparable>, E int getMessageCount(); - int getUndeliveredMessageCount(); - long getQueueDepth(); - long getReceivedMessageCount(); - long getOldestMessageArrivalTime(); boolean isDeleted(); int delete() throws AMQException; - void requeue(QueueEntry entry); + void requeue(E entry); - void dequeue(QueueEntry entry, Consumer sub); + void dequeue(E entry); - void decrementUnackedMsgCount(QueueEntry queueEntry); + void decrementUnackedMsgCount(E queueEntry); - boolean resend(final QueueEntry entry, final Consumer consumer) throws AMQException; + boolean resend(final E entry, final C consumer) throws AMQException; void addQueueDeleteTask(Action task); void removeQueueDeleteTask(Action task); - List getMessagesOnTheQueue(); - - List getMessagesOnTheQueue(long fromMessageId, long toMessageId); + List getMessagesOnTheQueue(); List getMessagesOnTheQueue(int num); List getMessagesOnTheQueue(int num, int offset); - QueueEntry getMessageOnTheQueue(long messageId); + E getMessageOnTheQueue(long messageId); /** * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. @@ -132,9 +126,9 @@ public interface AMQQueue extends Comparable>, E * @param toPosition * @return */ - public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition); + public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition); - void visit(QueueEntryVisitor visitor); + void visit(QueueEntryVisitor visitor); long getMaximumMessageSize(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 38c205bc00..4e0a9048e1 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -288,11 +288,11 @@ public class AMQQueueFactory implements QueueFactory } else if(priorities > 1) { - q = new AMQPriorityQueue(id, queueName, durable, owner, autoDelete, exclusive, _virtualHost, arguments, priorities); + q = new PriorityQueue(id, queueName, durable, owner, autoDelete, exclusive, _virtualHost, arguments, priorities); } else { - q = new SimpleAMQQueue(id, queueName, durable, owner, autoDelete, exclusive, _virtualHost, arguments); + q = new StandardQueue(id, queueName, durable, owner, autoDelete, exclusive, _virtualHost, arguments); } q.setDeleteOnNoConsumers(deleteOnNoConsumer); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java index a9b36c1b24..efc82c0ab4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AssignedConsumerMessageGroupManager.java @@ -28,7 +28,7 @@ import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; -public class AssignedConsumerMessageGroupManager implements MessageGroupManager +public class AssignedConsumerMessageGroupManager, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> implements MessageGroupManager { private static final Logger _logger = LoggerFactory.getLogger(AssignedConsumerMessageGroupManager.class); @@ -53,25 +53,18 @@ public class AssignedConsumerMessageGroupManager implements MessageGroupManager return val; } - public QueueConsumer getAssignedConsumer(final QueueEntry entry) + public QueueConsumer getAssignedConsumer(final E entry) { Object groupVal = entry.getMessage().getMessageHeader().getHeader(_groupId); return groupVal == null ? null : _groupMap.get(groupVal.hashCode() & _groupMask); } - public boolean acceptMessage(QueueConsumer sub, QueueEntry entry) + public boolean acceptMessage(QueueConsumer sub, E entry) { - if(assignMessage(sub, entry)) - { - return entry.acquire(sub); - } - else - { - return false; - } + return assignMessage(sub, entry) && entry.acquire(sub); } - private boolean assignMessage(QueueConsumer sub, QueueEntry entry) + private boolean assignMessage(QueueConsumer sub, E entry) { Object groupVal = entry.getMessage().getMessageHeader().getHeader(_groupId); if(groupVal == null) @@ -105,16 +98,16 @@ public class AssignedConsumerMessageGroupManager implements MessageGroupManager } } - public QueueEntry findEarliestAssignedAvailableEntry(QueueConsumer sub) + public E findEarliestAssignedAvailableEntry(QueueConsumer sub) { EntryFinder visitor = new EntryFinder(sub); sub.getQueue().visit(visitor); return visitor.getEntry(); } - private class EntryFinder implements QueueEntryVisitor + private class EntryFinder implements QueueEntryVisitor { - private QueueEntry _entry; + private E _entry; private QueueConsumer _sub; public EntryFinder(final QueueConsumer sub) @@ -122,7 +115,7 @@ public class AssignedConsumerMessageGroupManager implements MessageGroupManager _sub = sub; } - public boolean visit(final QueueEntry entry) + public boolean visit(final E entry) { if(!entry.isAvailable()) { @@ -148,7 +141,7 @@ public class AssignedConsumerMessageGroupManager implements MessageGroupManager } } - public QueueEntry getEntry() + public E getEntry() { return _entry; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java index c1c3bd37e6..31c54dcdd2 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java @@ -28,9 +28,9 @@ import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.store.TransactionLogResource; import org.apache.qpid.server.util.Action; -public interface BaseQueue extends TransactionLogResource +public interface BaseQueue extends TransactionLogResource { - void enqueue(ServerMessage message, Action> action) throws AMQException; + void enqueue(ServerMessage message, Action> action) throws AMQException; boolean isDurable(); boolean isDeleted(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java index c2813bb7a5..a1ff51959c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueue.java @@ -26,7 +26,7 @@ import java.util.UUID; import org.apache.qpid.server.virtualhost.VirtualHost; -public class ConflationQueue extends SimpleAMQQueue +public class ConflationQueue extends SimpleAMQQueue { protected ConflationQueue(UUID id, String name, @@ -42,7 +42,7 @@ public class ConflationQueue extends SimpleAMQQueue public String getConflationKey() { - return ((ConflationQueueList) getEntries()).getConflationKey(); + return getEntries().getConflationKey(); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java index 7469e95394..a98a4ac144 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java @@ -32,23 +32,38 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; -public class ConflationQueueList extends SimpleQueueEntryList +public class ConflationQueueList extends OrderedQueueEntryList { private static final Logger LOGGER = LoggerFactory.getLogger(ConflationQueueList.class); + private static final HeadCreator HEAD_CREATOR = new HeadCreator() + { + + @Override + public ConflationQueueEntry createHead(final ConflationQueueList list) + { + return list.createHead(); + } + }; + private final String _conflationKey; - private final ConcurrentHashMap> _latestValuesMap = - new ConcurrentHashMap>(); + private final ConcurrentHashMap> _latestValuesMap = + new ConcurrentHashMap>(); - private final QueueEntry _deleteInProgress = new SimpleQueueEntryImpl(this); - private final QueueEntry _newerEntryAlreadyBeenAndGone = new SimpleQueueEntryImpl(this); + private final ConflationQueueEntry _deleteInProgress = new ConflationQueueEntry(this); + private final ConflationQueueEntry _newerEntryAlreadyBeenAndGone = new ConflationQueueEntry(this); - public ConflationQueueList(AMQQueue queue, String conflationKey) + public ConflationQueueList(ConflationQueue queue, String conflationKey) { - super(queue); + super(queue, HEAD_CREATOR); _conflationKey = conflationKey; } + private ConflationQueueEntry createHead() + { + return new ConflationQueueEntry(this); + } + public String getConflationKey() { return _conflationKey; @@ -66,7 +81,7 @@ public class ConflationQueueList extends SimpleQueueEntryList @Override public ConflationQueueEntry add(final ServerMessage message) { - final ConflationQueueEntry addedEntry = (ConflationQueueEntry) (super.add(message)); + final ConflationQueueEntry addedEntry = super.add(message); final Object keyValue = message.getMessageHeader().getHeader(_conflationKey); if (keyValue != null) @@ -76,14 +91,14 @@ public class ConflationQueueList extends SimpleQueueEntryList LOGGER.debug("Adding entry " + addedEntry + " for message " + message.getMessageNumber() + " with conflation key " + keyValue); } - final AtomicReference referenceToEntry = new AtomicReference(addedEntry); - AtomicReference entryReferenceFromMap = null; - QueueEntry entryFromMap; + final AtomicReference referenceToEntry = new AtomicReference(addedEntry); + AtomicReference entryReferenceFromMap; + ConflationQueueEntry entryFromMap; // Iterate until we have got a valid atomic reference object and either the referent is newer than the current // entry, or the current entry has replaced it in the reference. Note that the _deletedEntryPlaceholder is a special value // indicating that the reference object is no longer valid (it is being removed from the map). - boolean keepTryingToUpdateEntryReference = true; + boolean keepTryingToUpdateEntryReference; do { do @@ -139,16 +154,16 @@ public class ConflationQueueList extends SimpleQueueEntryList * adds and removes during execution of this method. * */ - private AtomicReference getOrPutIfAbsent(final Object key, final AtomicReference referenceToAddedValue) + private AtomicReference getOrPutIfAbsent(final Object key, final AtomicReference referenceToAddedValue) { - AtomicReference latestValueReference = _latestValuesMap.putIfAbsent(key, referenceToAddedValue); + AtomicReference latestValueReference = _latestValuesMap.putIfAbsent(key, referenceToAddedValue); if(latestValueReference == null) { latestValueReference = _latestValuesMap.get(key); if(latestValueReference == null) { - return new AtomicReference(_newerEntryAlreadyBeenAndGone); + return new AtomicReference(_newerEntryAlreadyBeenAndGone); } } return latestValueReference; @@ -177,12 +192,17 @@ public class ConflationQueueList extends SimpleQueueEntryList } } - private final class ConflationQueueEntry extends SimpleQueueEntryImpl + final class ConflationQueueEntry extends OrderedQueueEntry { - private AtomicReference _latestValueReference; + private AtomicReference _latestValueReference; + + private ConflationQueueEntry(final ConflationQueueList queueEntryList) + { + super(queueEntryList); + } - public ConflationQueueEntry(SimpleQueueEntryList queueEntryList, ServerMessage message) + public ConflationQueueEntry(ConflationQueueList queueEntryList, ServerMessage message) { super(queueEntryList, message); } @@ -206,7 +226,7 @@ public class ConflationQueueList extends SimpleQueueEntryList } - public void setLatestValueReference(final AtomicReference latestValueReference) + public void setLatestValueReference(final AtomicReference latestValueReference) { _latestValueReference = latestValueReference; } @@ -227,12 +247,12 @@ public class ConflationQueueList extends SimpleQueueEntryList /** * Exposed purposes of unit test only. */ - Map> getLatestValuesMap() + Map> getLatestValuesMap() { return Collections.unmodifiableMap(_latestValuesMap); } - static class Factory implements QueueEntryListFactory + static class Factory implements QueueEntryListFactory { private final String _conflationKey; @@ -241,7 +261,8 @@ public class ConflationQueueList extends SimpleQueueEntryList _conflationKey = conflationKey; } - public ConflationQueueList createQueueEntryList(AMQQueue queue) + @Override + public ConflationQueueList createQueueEntryList(final ConflationQueue queue) { return new ConflationQueueList(queue, _conflationKey); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java index 4c74e5ba0b..e67591ae07 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java @@ -32,22 +32,22 @@ import org.apache.qpid.server.message.ServerMessage; import java.util.HashMap; import java.util.Map; -public class DefinedGroupMessageGroupManager implements MessageGroupManager +public class DefinedGroupMessageGroupManager, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> implements MessageGroupManager { private static final Logger _logger = LoggerFactory.getLogger(DefinedGroupMessageGroupManager.class); private final String _groupId; private final String _defaultGroup; private final Map _groupMap = new HashMap(); - private final ConsumerResetHelper _resetHelper; + private final ConsumerResetHelper _resetHelper; private final class Group { private final Object _group; - private QueueConsumer _consumer; + private QueueConsumer _consumer; private int _activeCount; - private Group(final Object key, final QueueConsumer consumer) + private Group(final Object key, final QueueConsumer consumer) { _group = key; _consumer = consumer; @@ -104,7 +104,7 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager return !(_consumer == null || (_activeCount == 0 && _consumer.isClosed())); } - public QueueConsumer getConsumer() + public QueueConsumer getConsumer() { return _consumer; } @@ -120,14 +120,14 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager } } - public DefinedGroupMessageGroupManager(final String groupId, String defaultGroup, ConsumerResetHelper resetHelper) + public DefinedGroupMessageGroupManager(final String groupId, String defaultGroup, ConsumerResetHelper resetHelper) { _groupId = groupId; _defaultGroup = defaultGroup; _resetHelper = resetHelper; } - public synchronized QueueConsumer getAssignedConsumer(final QueueEntry entry) + public synchronized QueueConsumer getAssignedConsumer(final E entry) { Object groupId = getKey(entry); @@ -135,19 +135,12 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager return group == null || !group.isValid() ? null : group.getConsumer(); } - public synchronized boolean acceptMessage(final QueueConsumer sub, final QueueEntry entry) + public synchronized boolean acceptMessage(final QueueConsumer sub, final E entry) { - if(assignMessage(sub, entry)) - { - return entry.acquire(sub); - } - else - { - return false; - } + return assignMessage(sub, entry) && entry.acquire(sub); } - private boolean assignMessage(final QueueConsumer sub, final QueueEntry entry) + private boolean assignMessage(final QueueConsumer sub, final E entry) { Object groupId = getKey(entry); Group group = _groupMap.get(groupId); @@ -171,7 +164,7 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager if(assignedSub == sub) { - entry.addStateChangeListener(new GroupStateChangeListener(group, entry)); + entry.addStateChangeListener(new GroupStateChangeListener(group)); return true; } else @@ -180,16 +173,16 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager } } - public synchronized QueueEntry findEarliestAssignedAvailableEntry(final QueueConsumer sub) + public synchronized E findEarliestAssignedAvailableEntry(final QueueConsumer sub) { EntryFinder visitor = new EntryFinder(sub); sub.getQueue().visit(visitor); return visitor.getEntry(); } - private class EntryFinder implements QueueEntryVisitor + private class EntryFinder implements QueueEntryVisitor { - private QueueEntry _entry; + private E _entry; private QueueConsumer _sub; public EntryFinder(final QueueConsumer sub) @@ -197,7 +190,7 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager _sub = sub; } - public boolean visit(final QueueEntry entry) + public boolean visit(final E entry) { if(!entry.isAvailable()) { @@ -218,7 +211,7 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager } } - public QueueEntry getEntry() + public E getEntry() { return _entry; } @@ -229,7 +222,7 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager { } - private Object getKey(QueueEntry entry) + private Object getKey(E entry) { ServerMessage message = entry.getMessage(); AMQMessageHeader messageHeader = message == null ? null : message.getMessageHeader(); @@ -241,17 +234,16 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager return groupVal; } - private class GroupStateChangeListener implements StateChangeListener, QueueEntry.State> + private class GroupStateChangeListener implements StateChangeListener, QueueEntry.State> { private final Group _group; - public GroupStateChangeListener(final Group group, - final MessageInstance entry) + public GroupStateChangeListener(final Group group) { _group = group; } - public void stateChanged(final MessageInstance entry, + public void stateChanged(final MessageInstance entry, final MessageInstance.State oldState, final MessageInstance.State newState) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/MessageGroupManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/MessageGroupManager.java index 740a96bf2d..ba9dbc8a70 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/MessageGroupManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/MessageGroupManager.java @@ -20,20 +20,20 @@ */ package org.apache.qpid.server.queue; -public interface MessageGroupManager +public interface MessageGroupManager, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { - public interface ConsumerResetHelper + public interface ConsumerResetHelper, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { - public void resetSubPointersForGroups(QueueConsumer consumer, boolean clearAssignments); + public void resetSubPointersForGroups(QueueConsumer consumer, boolean clearAssignments); - boolean isEntryAheadOfConsumer(QueueEntry entry, QueueConsumer sub); + boolean isEntryAheadOfConsumer(E entry, QueueConsumer sub); } - QueueConsumer getAssignedConsumer(QueueEntry entry); + QueueConsumer getAssignedConsumer(E entry); - boolean acceptMessage(QueueConsumer sub, QueueEntry entry); + boolean acceptMessage(QueueConsumer sub, E entry); - QueueEntry findEarliestAssignedAvailableEntry(QueueConsumer sub); + E findEarliestAssignedAvailableEntry(QueueConsumer sub); void clearAssignments(QueueConsumer sub); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java new file mode 100644 index 0000000000..369f42b183 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.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.queue; + +import org.apache.qpid.server.message.ServerMessage; + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +public abstract class OrderedQueueEntry, Q extends SimpleAMQQueue, L extends OrderedQueueEntryList> extends QueueEntryImpl +{ + static final AtomicReferenceFieldUpdater + _nextUpdater = + AtomicReferenceFieldUpdater.newUpdater + (OrderedQueueEntry.class, OrderedQueueEntry.class, "_next"); + + private volatile E _next; + + public OrderedQueueEntry(L queueEntryList) + { + super(queueEntryList); + } + + public OrderedQueueEntry(L queueEntryList, ServerMessage message, final long entryId) + { + super(queueEntryList, message, entryId); + } + + public OrderedQueueEntry(L queueEntryList, ServerMessage message) + { + super(queueEntryList, message); + } + + public E getNextNode() + { + return _next; + } + + public E getNextValidEntry() + { + + E next = getNextNode(); + while(next != null && next.isDeleted()) + { + + final E newNext = next.getNextNode(); + if(newNext != null) + { + OrderedQueueEntryList._nextUpdater.compareAndSet(this,next, newNext); + next = getNextNode(); + } + else + { + next = null; + } + + } + return next; + } + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java new file mode 100644 index 0000000000..f2491bdb0c --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java @@ -0,0 +1,198 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.message.ServerMessage; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +public abstract class OrderedQueueEntryList, Q extends SimpleAMQQueue, L extends OrderedQueueEntryList> implements SimpleQueueEntryList +{ + + private final E _head; + + private volatile E _tail; + + static final AtomicReferenceFieldUpdater + _tailUpdater = + AtomicReferenceFieldUpdater.newUpdater + (OrderedQueueEntryList.class, OrderedQueueEntry.class, "_tail"); + + + private final Q _queue; + + static final AtomicReferenceFieldUpdater + _nextUpdater = OrderedQueueEntry._nextUpdater; + + private AtomicLong _scavenges = new AtomicLong(0L); + private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50); + private final AtomicReference _unscavengedHWM = new AtomicReference(); + + + public OrderedQueueEntryList(Q queue, HeadCreator headCreator) + { + _queue = queue; + _head = headCreator.createHead((L)this); + _tail = _head; + } + + void scavenge() + { + E hwm = _unscavengedHWM.getAndSet(null); + E next = _head.getNextValidEntry(); + + if(hwm != null) + { + while (next != null && hwm.compareTo(next)>0) + { + next = next.getNextValidEntry(); + } + } + } + + + public Q getQueue() + { + return _queue; + } + + + public E add(ServerMessage message) + { + E node = createQueueEntry(message); + for (;;) + { + OrderedQueueEntry tail = _tail; + OrderedQueueEntry next = tail.getNextNode(); + 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); + } + } + } + } + + abstract protected E createQueueEntry(ServerMessage message); + + public E next(E node) + { + return node.getNextValidEntry(); + } + + public static interface HeadCreator, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> + { + E createHead(L list); + } + + public static class QueueEntryIteratorImpl, Q extends SimpleAMQQueue, L extends OrderedQueueEntryList> implements QueueEntryIterator> + { + private E _lastNode; + + QueueEntryIteratorImpl(E startNode) + { + _lastNode = startNode; + } + + public boolean atTail() + { + return _lastNode.getNextValidEntry() == null; + } + + public E getNode() + { + return _lastNode; + } + + public boolean advance() + { + E nextValidNode = _lastNode.getNextValidEntry(); + + if(nextValidNode != null) + { + _lastNode = nextValidNode; + } + + return nextValidNode != null; + } + } + + public QueueEntryIterator> iterator() + { + return new QueueEntryIteratorImpl(_head); + } + + + public E getHead() + { + return _head; + } + + public void entryDeleted(E queueEntry) + { + E next = _head.getNextNode(); + E newNext = _head.getNextValidEntry(); + + // the head of the queue has not been deleted, hence the deletion must have been mid queue. + if (next == newNext) + { + E unscavengedHWM = _unscavengedHWM.get(); + while(unscavengedHWM == null || unscavengedHWM.compareTo(queueEntry)<0) + { + _unscavengedHWM.compareAndSet(unscavengedHWM, queueEntry); + unscavengedHWM = _unscavengedHWM.get(); + } + if (_scavenges.incrementAndGet() > _scavengeCount) + { + _scavenges.set(0L); + scavenge(); + } + } + else + { + E unscavengedHWM = _unscavengedHWM.get(); + if(unscavengedHWM != null && (next == null || unscavengedHWM.compareTo(next) < 0)) + { + _unscavengedHWM.compareAndSet(unscavengedHWM, null); + } + } + } + + public int getPriorities() + { + return 0; + } + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java index 6918ae683c..7cf245c8f8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java @@ -25,30 +25,30 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; import java.util.UUID; -public abstract class OutOfOrderQueue extends SimpleAMQQueue +public abstract class OutOfOrderQueue, Q extends OutOfOrderQueue, L extends SimpleQueueEntryList> extends SimpleAMQQueue { protected OutOfOrderQueue(UUID id, String name, boolean durable, String owner, boolean autoDelete, boolean exclusive, - VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map arguments) + VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map arguments) { super(id, name, durable, owner, autoDelete, exclusive, virtualHost, entryListFactory, arguments); } @Override - protected void checkConsumersNotAheadOfDelivery(final QueueEntry entry) + protected void checkConsumersNotAheadOfDelivery(final E entry) { // check that all consumers are not in advance of the entry - QueueConsumerList.ConsumerNodeIterator subIter = getConsumerList().iterator(); + QueueConsumerList.ConsumerNodeIterator subIter = getConsumerList().iterator(); while(subIter.advance() && !entry.isAcquired()) { - final QueueConsumer consumer = subIter.getNode().getConsumer(); + final QueueConsumer consumer = subIter.getNode().getConsumer(); if(!consumer.isClosed()) { - QueueContext context = consumer.getQueueContext(); + QueueContext context = consumer.getQueueContext(); if(context != null) { - QueueEntry released = context.getReleasedEntry(); + E released = context.getReleasedEntry(); while(!entry.isAcquired() && (released == null || released.compareTo(entry) > 0)) { if(QueueContext._releasedUpdater.compareAndSet(context,released,entry)) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueue.java new file mode 100644 index 0000000000..4440d045d1 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueue.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.virtualhost.VirtualHost; + +import java.util.Map; +import java.util.UUID; + +public class PriorityQueue extends OutOfOrderQueue +{ + protected PriorityQueue(UUID id, + final String name, + final boolean durable, + final String owner, + final boolean autoDelete, + boolean exclusive, + final VirtualHost virtualHost, + Map arguments, int priorities) + { + super(id, name, durable, owner, autoDelete, exclusive, virtualHost, new PriorityQueueList.Factory(priorities), arguments); + } + + public int getPriorities() + { + return getEntries().getPriorities(); + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java index 05d84327d4..e877983643 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -22,132 +22,162 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.message.ServerMessage; -public class PriorityQueueList implements QueueEntryList +abstract public class PriorityQueueList extends OrderedQueueEntryList { - private final AMQQueue _queue; - private final PriorityQueueEntrySubList[] _priorityLists; - private final int _priorities; - private final int _priorityOffset; - public PriorityQueueList(AMQQueue queue, int priorities) - { - _queue = queue; - _priorityLists = new PriorityQueueEntrySubList[priorities]; - _priorities = priorities; - _priorityOffset = 5-((priorities + 1)/2); - for(int i = 0; i < priorities; i++) - { - _priorityLists[i] = new PriorityQueueEntrySubList(queue, i); - } - } - public int getPriorities() + public PriorityQueueList(final PriorityQueue queue, + final HeadCreator headCreator) { - return _priorities; + super(queue, headCreator); } - public AMQQueue getQueue() + static class PriorityQueueMasterList extends PriorityQueueList { - return _queue; - } + private static final HeadCreator DUMMY_HEAD_CREATOR = + new HeadCreator() + { + @Override + public PriorityQueueEntry createHead(final PriorityQueueList list) + { + return null; + } + }; + private final PriorityQueue _queue; + private final PriorityQueueEntrySubList[] _priorityLists; + private final int _priorities; + private final int _priorityOffset; - public SimpleQueueEntryImpl add(ServerMessage message) - { - int index = message.getMessageHeader().getPriority() - _priorityOffset; - if(index >= _priorities) + public PriorityQueueMasterList(PriorityQueue queue, int priorities) { - index = _priorities-1; + super(queue, DUMMY_HEAD_CREATOR); + _queue = queue; + _priorityLists = new PriorityQueueEntrySubList[priorities]; + _priorities = priorities; + _priorityOffset = 5-((priorities + 1)/2); + for(int i = 0; i < priorities; i++) + { + _priorityLists[i] = new PriorityQueueEntrySubList(queue, i); + } } - else if(index < 0) + + public int getPriorities() { - index = 0; + return _priorities; } - return _priorityLists[index].add(message); - - } - - public SimpleQueueEntryImpl next(SimpleQueueEntryImpl node) - { - SimpleQueueEntryImpl next = node.getNextValidEntry(); - if(next == null) + public PriorityQueue getQueue() { - final QueueEntryList nodeEntryList = node.getQueueEntryList(); - int index; - for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--) {}; + return _queue; + } - while(next == null && index != 0) + public PriorityQueueEntry add(ServerMessage message) + { + int index = message.getMessageHeader().getPriority() - _priorityOffset; + if(index >= _priorities) + { + index = _priorities-1; + } + else if(index < 0) { - index--; - next = _priorityLists[index].getHead().getNextValidEntry(); + index = 0; } + return _priorityLists[index].add(message); } - return next; - } - private final class PriorityQueueEntryListIterator implements QueueEntryIterator - { - private final SimpleQueueEntryList.QueueEntryIteratorImpl[] _iterators = new SimpleQueueEntryList.QueueEntryIteratorImpl[ _priorityLists.length ]; - private SimpleQueueEntryImpl _lastNode; + @Override + protected PriorityQueueEntry createQueueEntry(final ServerMessage message) + { + throw new UnsupportedOperationException(); + } - PriorityQueueEntryListIterator() + public PriorityQueueEntry next(PriorityQueueEntry node) { - for(int i = 0; i < _priorityLists.length; i++) + PriorityQueueEntry next = node.getNextValidEntry(); + + if(next == null) { - _iterators[i] = _priorityLists[i].iterator(); + final PriorityQueueList nodeEntryList = node.getQueueEntryList(); + int index; + for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--) + { + // do nothing loop is just to find the index + } + + while(next == null && index != 0) + { + index--; + next = _priorityLists[index].getHead().getNextValidEntry(); + } + } - _lastNode = _iterators[_iterators.length - 1].getNode(); + return next; } - - public boolean atTail() + private final class PriorityQueueEntryListIterator implements QueueEntryIterator> { - for(int i = 0; i < _iterators.length; i++) + private final QueueEntryIterator>[] _iterators = new QueueEntryIterator[ _priorityLists.length ]; + private PriorityQueueEntry _lastNode; + + PriorityQueueEntryListIterator() { - if(!_iterators[i].atTail()) + for(int i = 0; i < _priorityLists.length; i++) { - return false; + _iterators[i] = _priorityLists[i].iterator(); } + _lastNode = _iterators[_iterators.length - 1].getNode(); } - return true; - } - public SimpleQueueEntryImpl getNode() - { - return _lastNode; - } - public boolean advance() - { - for(int i = _iterators.length-1; i >= 0; i--) + public boolean atTail() { - if(_iterators[i].advance()) + for(int i = 0; i < _iterators.length; i++) { - _lastNode = _iterators[i].getNode(); - return true; + if(!_iterators[i].atTail()) + { + return false; + } } + return true; + } + + public PriorityQueueEntry 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; } - return false; } - } - public PriorityQueueEntryListIterator iterator() - { - return new PriorityQueueEntryListIterator(); - } + public PriorityQueueEntryListIterator iterator() + { - public SimpleQueueEntryImpl getHead() - { - return _priorityLists[_priorities-1].getHead(); - } + return new PriorityQueueEntryListIterator(); + } - public void entryDeleted(final SimpleQueueEntryImpl queueEntry) - { + public PriorityQueueEntry getHead() + { + return _priorityLists[_priorities-1].getHead(); + } - } + public void entryDeleted(final PriorityQueueEntry queueEntry) + { - static class Factory implements QueueEntryListFactory + } + } + static class Factory implements QueueEntryListFactory { private final int _priorities; @@ -156,26 +186,34 @@ public class PriorityQueueList implements QueueEntryList _priorities = priorities; } - public PriorityQueueList createQueueEntryList(AMQQueue queue) + public PriorityQueueList createQueueEntryList(PriorityQueue queue) { - return new PriorityQueueList(queue, _priorities); + return new PriorityQueueMasterList(queue, _priorities); } } - private static class PriorityQueueEntrySubList extends SimpleQueueEntryList + static class PriorityQueueEntrySubList extends PriorityQueueList { + private static final HeadCreator HEAD_CREATOR = new HeadCreator() + { + @Override + public PriorityQueueEntry createHead(final PriorityQueueList list) + { + return new PriorityQueueEntry(list); + } + }; private int _listPriority; - public PriorityQueueEntrySubList(AMQQueue queue, int listPriority) + public PriorityQueueEntrySubList(PriorityQueue queue, int listPriority) { - super(queue); + super(queue, HEAD_CREATOR); _listPriority = listPriority; } @Override - protected PriorityQueueEntryImpl createQueueEntry(ServerMessage message) + protected PriorityQueueEntry createQueueEntry(ServerMessage message) { - return new PriorityQueueEntryImpl(this, message); + return new PriorityQueueEntry(this, message); } public int getListPriority() @@ -184,17 +222,22 @@ public class PriorityQueueList implements QueueEntryList } } - private static class PriorityQueueEntryImpl extends SimpleQueueEntryImpl + static class PriorityQueueEntry extends OrderedQueueEntry { - public PriorityQueueEntryImpl(PriorityQueueEntrySubList queueEntryList, ServerMessage message) + private PriorityQueueEntry(final PriorityQueueList queueEntryList) + { + super(queueEntryList); + } + + public PriorityQueueEntry(PriorityQueueEntrySubList queueEntryList, ServerMessage message) { super(queueEntryList, message); } @Override - public int compareTo(final QueueEntry o) + public int compareTo(final PriorityQueueEntry o) { - PriorityQueueEntrySubList pqel = (PriorityQueueEntrySubList)((PriorityQueueEntryImpl)o).getQueueEntryList(); + PriorityQueueEntrySubList pqel = (PriorityQueueEntrySubList)o.getQueueEntryList(); int otherPriority = pqel.getListPriority(); int thisPriority = ((PriorityQueueEntrySubList) getQueueEntryList()).getListPriority(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java index ff7840255a..5c891797f5 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java @@ -47,7 +47,7 @@ import java.util.concurrent.locks.ReentrantLock; import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SUBSCRIPTION_FORMAT; -class QueueConsumer implements Consumer +class QueueConsumer, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> implements Consumer { public static enum State @@ -61,10 +61,9 @@ class QueueConsumer implements Consumer private final AtomicBoolean _targetClosed = new AtomicBoolean(false); private final AtomicBoolean _closed = new AtomicBoolean(false); private final long _id; - private final AtomicReference _state = new AtomicReference(State.ACTIVE); private final Lock _stateChangeLock = new ReentrantLock(); private final long _createTime = System.currentTimeMillis(); - private final MessageInstance.ConsumerAcquiredState _owningState = new MessageInstance.ConsumerAcquiredState(this); + private final MessageInstance.ConsumerAcquiredState> _owningState = new MessageInstance.ConsumerAcquiredState>(this); private final boolean _acquires; private final boolean _seesRequeues; private final String _consumerName; @@ -74,8 +73,10 @@ class QueueConsumer implements Consumer private final FilterManager _filters; private final Class _messageClass; private final Object _sessionReference; - private SimpleAMQQueue _queue; - private GenericActor _logActor; + private Q _queue; + private GenericActor _logActor = new GenericActor("[" + MessageFormat.format(SUBSCRIPTION_FORMAT, getId()) + + "(UNKNOWN)" + + "] "); static final EnumMap STATE_MAP = new EnumMap(ConsumerTarget.State.class); @@ -89,10 +90,10 @@ class QueueConsumer implements Consumer private final T _target; private final SubFlushRunner _runner = new SubFlushRunner(this); - private volatile QueueContext _queueContext; - private StateChangeListener _stateListener = new StateChangeListener() + private volatile QueueContext _queueContext; + private StateChangeListener, State> _stateListener = new StateChangeListener, State>() { - public void stateChanged(Consumer sub, State oldState, State newState) + public void stateChanged(QueueConsumer sub, State oldState, State newState) { CurrentActor.get().message(SubscriptionMessages.STATE(newState.toString())); } @@ -158,8 +159,7 @@ class QueueConsumer implements Consumer throw new RuntimeException(e); } } - final StateChangeListener stateListener = - (StateChangeListener) getStateListener(); + final StateChangeListener, State> stateListener = getStateListener(); if(stateListener != null) { stateListener.stateChanged(this, STATE_MAP.get(oldState), STATE_MAP.get(newState)); @@ -251,12 +251,12 @@ class QueueConsumer implements Consumer return STATE_MAP.get(_target.getState()); } - public final SimpleAMQQueue getQueue() + public final Q getQueue() { return _queue; } - final void setQueue(SimpleAMQQueue queue, boolean exclusive) + final void setQueue(Q queue, boolean exclusive) { if(getQueue() != null) { @@ -300,9 +300,9 @@ class QueueConsumer implements Consumer getQueue().flushConsumer(this); } - boolean resend(final MessageInstance entry) throws AMQException + boolean resend(final E entry) throws AMQException { - return getQueue().resend((QueueEntry)entry, this); + return getQueue().resend(entry, this); } final SubFlushRunner getRunner() @@ -315,31 +315,26 @@ class QueueConsumer implements Consumer return _id; } - public final StateChangeListener getStateListener() + public final StateChangeListener, State> getStateListener() { return _stateListener; } - public final void setStateListener(StateChangeListener listener) + public final void setStateListener(StateChangeListener, State> listener) { _stateListener = listener; } - final QueueContext getQueueContext() + final QueueContext getQueueContext() { return _queueContext; } - final void setQueueContext(QueueContext queueContext) + final void setQueueContext(QueueContext queueContext) { _queueContext = queueContext; } - protected boolean updateState(State from, State to) - { - return _state.compareAndSet(from, to); - } - public final boolean isActive() { return getState() == State.ACTIVE; @@ -355,7 +350,7 @@ class QueueConsumer implements Consumer _noLocal = noLocal; } - public final boolean hasInterest(MessageInstance entry) + public final boolean hasInterest(E entry) { //check that the message hasn't been rejected if (entry.isRejectedBy(this)) @@ -405,7 +400,6 @@ class QueueConsumer implements Consumer filterLogString.append(delimiter); } filterLogString.append("Browser"); - hasEntries = true; } return filterLogString.toString(); @@ -431,7 +425,7 @@ class QueueConsumer implements Consumer return _createTime; } - final MessageInstance.ConsumerAcquiredState getOwningState() + final MessageInstance.ConsumerAcquiredState> getOwningState() { return _owningState; } @@ -466,7 +460,7 @@ class QueueConsumer implements Consumer return _deliveredCount.longValue(); } - final void send(final QueueEntry entry, final boolean batch) throws AMQException + final void send(final E entry, final boolean batch) throws AMQException { _deliveredCount.incrementAndGet(); ServerMessage message = entry.getMessage(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerList.java index 82e9d58cf3..2cf0e93e9c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerList.java @@ -24,19 +24,19 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -class QueueConsumerList +class QueueConsumerList, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { - private final ConsumerNode _head = new ConsumerNode(); + private final ConsumerNode _head = new ConsumerNode(); - private final AtomicReference _tail = new AtomicReference(_head); - private final AtomicReference _subNodeMarker = new AtomicReference(_head); + private final AtomicReference> _tail = new AtomicReference>(_head); + private final AtomicReference> _subNodeMarker = new AtomicReference>(_head); private final AtomicInteger _size = new AtomicInteger(); - public static final class ConsumerNode + public static final class ConsumerNode, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { private final AtomicBoolean _deleted = new AtomicBoolean(); - private final AtomicReference _next = new AtomicReference(); - private final QueueConsumer _sub; + private final AtomicReference> _next = new AtomicReference>(); + private final QueueConsumer _sub; public ConsumerNode() { @@ -45,7 +45,7 @@ class QueueConsumerList _deleted.set(true); } - public ConsumerNode(final QueueConsumer sub) + public ConsumerNode(final QueueConsumer sub) { //used for regular node construction _sub = sub; @@ -57,12 +57,12 @@ class QueueConsumerList * * @return the next non-deleted node, or null if none was found. */ - public ConsumerNode findNext() + public ConsumerNode findNext() { - ConsumerNode next = nextNode(); + ConsumerNode next = nextNode(); while(next != null && next.isDeleted()) { - final ConsumerNode newNext = next.nextNode(); + final ConsumerNode newNext = next.nextNode(); if(newNext != null) { //try to move our _next reference forward to the 'newNext' @@ -86,7 +86,7 @@ class QueueConsumerList * * @return the immediately next node in the structure, or null if at the tail. */ - protected ConsumerNode nextNode() + protected ConsumerNode nextNode() { return _next.get(); } @@ -97,7 +97,7 @@ class QueueConsumerList * @param node the ConsumerNode to set as 'next' * @return whether the operation succeeded */ - private boolean setNext(final ConsumerNode node) + private boolean setNext(final ConsumerNode node) { return _next.compareAndSet(null, node); } @@ -112,18 +112,18 @@ class QueueConsumerList return _deleted.compareAndSet(false,true); } - public QueueConsumer getConsumer() + public QueueConsumer getConsumer() { return _sub; } } - private void insert(final ConsumerNode node, final boolean count) + private void insert(final ConsumerNode node, final boolean count) { for (;;) { - ConsumerNode tail = _tail.get(); - ConsumerNode next = tail.nextNode(); + ConsumerNode tail = _tail.get(); + ConsumerNode next = tail.nextNode(); if (tail == _tail.get()) { if (next == null) @@ -146,16 +146,16 @@ class QueueConsumerList } } - public void add(final QueueConsumer sub) + public void add(final QueueConsumer sub) { - ConsumerNode node = new ConsumerNode(sub); + ConsumerNode node = new ConsumerNode(sub); insert(node, true); } - public boolean remove(final QueueConsumer sub) + public boolean remove(final QueueConsumer sub) { - ConsumerNode prevNode = _head; - ConsumerNode node = _head.nextNode(); + ConsumerNode prevNode = _head; + ConsumerNode node = _head.nextNode(); while(node != null) { @@ -170,7 +170,7 @@ class QueueConsumerList //correctness reasons, however we have just 'deleted' //the tail. Inserting an empty dummy node after it will //let us scavenge the node containing the Consumer. - insert(new ConsumerNode(), false); + insert(new ConsumerNode(), false); } //advance the next node reference in the 'prevNode' to scavenge @@ -189,9 +189,9 @@ class QueueConsumerList return false; } - private void nodeMarkerCleanup(final ConsumerNode node) + private void nodeMarkerCleanup(final ConsumerNode node) { - ConsumerNode markedNode = _subNodeMarker.get(); + ConsumerNode markedNode = _subNodeMarker.get(); if(node == markedNode) { //if the marked node is the one we are removing, then @@ -200,7 +200,7 @@ class QueueConsumerList //into the list and find the next node to use. //Because we inserted a dummy if node was the //tail, markedNode.nextNode() can never be null. - ConsumerNode dummy = new ConsumerNode(); + ConsumerNode dummy = new ConsumerNode(); dummy.setNext(markedNode.nextNode()); //if the CAS fails the marked node has changed, thus @@ -219,7 +219,7 @@ class QueueConsumerList } } - public boolean updateMarkedNode(final ConsumerNode expected, final ConsumerNode nextNode) + public boolean updateMarkedNode(final ConsumerNode expected, final ConsumerNode nextNode) { return _subNodeMarker.compareAndSet(expected, nextNode); } @@ -231,41 +231,41 @@ class QueueConsumerList * * @return the previously marked node (or a dummy if it was subsequently deleted) */ - public ConsumerNode getMarkedNode() + public ConsumerNode getMarkedNode() { return _subNodeMarker.get(); } - public static class ConsumerNodeIterator + public static class ConsumerNodeIterator, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { - private ConsumerNode _lastNode; + private ConsumerNode _lastNode; - ConsumerNodeIterator(ConsumerNode startNode) + ConsumerNodeIterator(ConsumerNode startNode) { _lastNode = startNode; } - public ConsumerNode getNode() + public ConsumerNode getNode() { return _lastNode; } public boolean advance() { - ConsumerNode nextNode = _lastNode.findNext(); + ConsumerNode nextNode = _lastNode.findNext(); _lastNode = nextNode; return _lastNode != null; } } - public ConsumerNodeIterator iterator() + public ConsumerNodeIterator iterator() { - return new ConsumerNodeIterator(_head); + return new ConsumerNodeIterator(_head); } - public ConsumerNode getHead() + public ConsumerNode getHead() { return _head; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueContext.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueContext.java index 861bd3dea1..7a59c154b6 100755 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueContext.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueContext.java @@ -23,32 +23,32 @@ package org.apache.qpid.server.queue; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -final class QueueContext +final class QueueContext, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { - private volatile QueueEntry _lastSeenEntry; - private volatile QueueEntry _releasedEntry; + private volatile E _lastSeenEntry; + private volatile E _releasedEntry; - static final AtomicReferenceFieldUpdater + static final AtomicReferenceFieldUpdater _lastSeenUpdater = AtomicReferenceFieldUpdater.newUpdater - (QueueContext.class, QueueEntry.class, "_lastSeenEntry"); - static final AtomicReferenceFieldUpdater + (QueueContext.class, QueueEntryImpl.class, "_lastSeenEntry"); + static final AtomicReferenceFieldUpdater _releasedUpdater = AtomicReferenceFieldUpdater.newUpdater - (QueueContext.class, QueueEntry.class, "_releasedEntry"); + (QueueContext.class, QueueEntryImpl.class, "_releasedEntry"); - public QueueContext(QueueEntry head) + public QueueContext(E head) { _lastSeenEntry = head; } - public QueueEntry getLastSeenEntry() + public E getLastSeenEntry() { return _lastSeenEntry; } - QueueEntry getReleasedEntry() + E getReleasedEntry() { return _releasedEntry; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 6a42088c47..9a49cd6088 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -20,20 +20,21 @@ */ package org.apache.qpid.server.queue; +import org.apache.qpid.server.consumer.Consumer; import org.apache.qpid.server.message.MessageInstance; -public interface QueueEntry extends MessageInstance, Comparable +public interface QueueEntry, Q extends AMQQueue, C extends Consumer> extends MessageInstance, Comparable { - AMQQueue getQueue(); + Q getQueue(); long getSize(); boolean isQueueDeleted(); - QueueEntry getNextNode(); + E getNextNode(); - QueueEntry getNextValidEntry(); + E getNextValidEntry(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 4ee9df5e5d..173705c0f7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -44,11 +44,11 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -public abstract class QueueEntryImpl implements QueueEntry +public abstract class QueueEntryImpl, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> implements QueueEntry> { private static final Logger _log = Logger.getLogger(QueueEntryImpl.class); - private final QueueEntryList _queueEntryList; + private final L _queueEntryList; private final MessageReference _message; @@ -63,7 +63,7 @@ public abstract class QueueEntryImpl implements QueueEntry (QueueEntryImpl.class, EntryState.class, "_state"); - private volatile Set, State>> _stateChangeListeners; + private volatile Set> _stateChangeListeners; private static final AtomicReferenceFieldUpdater @@ -90,14 +90,14 @@ public abstract class QueueEntryImpl implements QueueEntry private boolean _deliveredToConsumer; - public QueueEntryImpl(QueueEntryList queueEntryList) + public QueueEntryImpl(L queueEntryList) { this(queueEntryList,null,Long.MIN_VALUE); _state = DELETED_STATE; } - public QueueEntryImpl(QueueEntryList queueEntryList, ServerMessage message, final long entryId) + public QueueEntryImpl(L queueEntryList, ServerMessage message, final long entryId) { _queueEntryList = queueEntryList; @@ -107,7 +107,7 @@ public abstract class QueueEntryImpl implements QueueEntry populateInstanceProperties(); } - public QueueEntryImpl(QueueEntryList queueEntryList, ServerMessage message) + public QueueEntryImpl(L queueEntryList, ServerMessage message) { _queueEntryList = queueEntryList; _message = message == null ? null : message.newReference(); @@ -138,7 +138,7 @@ public abstract class QueueEntryImpl implements QueueEntry return _entryId; } - public AMQQueue getQueue() + public Q getQueue() { return _queueEntryList.getQueue(); } @@ -234,12 +234,12 @@ public abstract class QueueEntryImpl implements QueueEntry if(state instanceof ConsumerAcquiredState) { - getQueue().decrementUnackedMsgCount(this); + getQueue().decrementUnackedMsgCount((E) this); } if(!getQueue().isDeleted()) { - getQueue().requeue(this); + getQueue().requeue((E)this); if(_stateChangeListeners != null) { notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); @@ -315,13 +315,12 @@ public abstract class QueueEntryImpl implements QueueEntry if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) { - Consumer s = null; if (state instanceof ConsumerAcquiredState) { - getQueue().decrementUnackedMsgCount(this); + getQueue().decrementUnackedMsgCount((E) this); } - getQueue().dequeue(this,s); + getQueue().dequeue((E)this); if(_stateChangeListeners != null) { notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); @@ -333,9 +332,9 @@ public abstract class QueueEntryImpl implements QueueEntry private void notifyStateChange(final State oldState, final State newState) { - for(StateChangeListener, State> l : _stateChangeListeners) + for(StateChangeListener l : _stateChangeListeners) { - l.stateChanged(this, oldState, newState); + l.stateChanged((E)this, oldState, newState); } } @@ -345,7 +344,7 @@ public abstract class QueueEntryImpl implements QueueEntry if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) { - _queueEntryList.entryDeleted(this); + _queueEntryList.entryDeleted((E)this); onDelete(); _message.release(); @@ -364,7 +363,7 @@ public abstract class QueueEntryImpl implements QueueEntry dispose(); } - public int routeToAlternate(final Action> action, ServerTransaction txn) + public int routeToAlternate(final Action> action, ServerTransaction txn) { final AMQQueue currentQueue = getQueue(); Exchange alternateExchange = currentQueue.getAlternateExchange(); @@ -378,11 +377,10 @@ public abstract class QueueEntryImpl implements QueueEntry if (alternateExchange != null) { - enqueues = alternateExchange.send(getMessage(), - getInstanceProperties(), - txn, - action); + getInstanceProperties(), + txn, + action); } else { @@ -406,8 +404,8 @@ public abstract class QueueEntryImpl implements QueueEntry { txn.commit(); } - return enqueues; + return enqueues; } public boolean isQueueDeleted() @@ -415,21 +413,21 @@ public abstract class QueueEntryImpl implements QueueEntry return getQueue().isDeleted(); } - public void addStateChangeListener(StateChangeListener, State> listener) + public void addStateChangeListener(StateChangeListener listener) { - Set, State>> listeners = _stateChangeListeners; + Set> listeners = _stateChangeListeners; if(listeners == null) { - _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet, State>>()); + _listenersUpdater.compareAndSet(this, null, new CopyOnWriteArraySet>()); listeners = _stateChangeListeners; } listeners.add(listener); } - public boolean removeStateChangeListener(StateChangeListener, State> listener) + public boolean removeStateChangeListener(StateChangeListener listener) { - Set, State>> listeners = _stateChangeListeners; + Set> listeners = _stateChangeListeners; if(listeners != null) { return listeners.remove(listener); @@ -439,9 +437,9 @@ public abstract class QueueEntryImpl implements QueueEntry } - public int compareTo(final QueueEntry o) + public int compareTo(final E o) { - QueueEntryImpl other = (QueueEntryImpl)o; + E other = o; return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0; } @@ -449,7 +447,7 @@ public abstract class QueueEntryImpl implements QueueEntry { } - public QueueEntryList getQueueEntryList() + public L getQueueEntryList() { return _queueEntryList; } @@ -497,10 +495,10 @@ public abstract class QueueEntryImpl implements QueueEntry @Override public boolean resend() throws AMQException { - QueueConsumer sub = getDeliveredConsumer(); + QueueConsumer sub = getDeliveredConsumer(); if(sub != null) { - return sub.resend(this); + return sub.resend((E)this); } return false; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java index 73ebb0f300..72502feb3d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java @@ -20,11 +20,13 @@ */ package org.apache.qpid.server.queue; -public interface QueueEntryIterator +import org.apache.qpid.server.consumer.Consumer; + +public interface QueueEntryIterator, Q extends AMQQueue, L extends QueueEntryList, C extends Consumer> { boolean atTail(); - QE getNode(); + E getNode(); boolean advance(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java index ad1f703f51..a49320e9d6 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -20,21 +20,23 @@ */ package org.apache.qpid.server.queue; +import org.apache.qpid.server.consumer.Consumer; import org.apache.qpid.server.message.ServerMessage; -public interface QueueEntryList +public interface QueueEntryList, Q extends AMQQueue, L extends QueueEntryList, C extends Consumer> { - AMQQueue getQueue(); + Q getQueue(); - Q add(ServerMessage message); + E add(ServerMessage message); - Q next(Q node); + E next(E node); - QueueEntryIterator iterator(); + QueueEntryIterator iterator(); - Q getHead(); + E getHead(); - void entryDeleted(Q queueEntry); + void entryDeleted(E queueEntry); int getPriorities(); + } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java index 4dbce45f67..ae8b6560be 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListFactory.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.queue; -interface QueueEntryListFactory +interface QueueEntryListFactory, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> { - public QueueEntryList createQueueEntryList(AMQQueue queue); + public L createQueueEntryList(Q queue); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryVisitor.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryVisitor.java index 9ecaf6dafd..e6b5ac5611 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryVisitor.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryVisitor.java @@ -16,7 +16,9 @@ */ package org.apache.qpid.server.queue; -public interface QueueEntryVisitor +import org.apache.qpid.server.consumer.Consumer; + +public interface QueueEntryVisitor { - boolean visit(QueueEntry entry); + boolean visit(E entry); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index f4a9794fcd..4450a3ed0c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -43,7 +43,6 @@ 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.message.InstanceProperties; -import org.apache.qpid.server.message.MessageDestination; import org.apache.qpid.server.message.MessageInstance; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; @@ -52,6 +51,7 @@ import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.security.AuthorizationHolder; import org.apache.qpid.server.consumer.Consumer; import org.apache.qpid.server.consumer.ConsumerTarget; +import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.server.txn.ServerTransaction; @@ -59,9 +59,9 @@ import org.apache.qpid.server.util.Action; import org.apache.qpid.server.util.StateChangeListener; import org.apache.qpid.server.virtualhost.VirtualHost; -public class SimpleAMQQueue implements AMQQueue, - StateChangeListener, - MessageGroupManager.ConsumerResetHelper +abstract class SimpleAMQQueue, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> implements AMQQueue>, + StateChangeListener, QueueConsumer.State>, + MessageGroupManager.ConsumerResetHelper { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); @@ -94,11 +94,11 @@ public class SimpleAMQQueue implements AMQQueue, private Exchange _alternateExchange; - private final QueueEntryList _entries; + private final L _entries; - private final QueueConsumerList _consumerList = new QueueConsumerList(); + private final QueueConsumerList _consumerList = new QueueConsumerList(); - private volatile QueueConsumer _exclusiveSubscriber; + private volatile QueueConsumer _exclusiveSubscriber; @@ -163,8 +163,7 @@ public class SimpleAMQQueue implements AMQQueue, private LogSubject _logSubject; private LogActor _logActor; - private static final String SUB_FLUSH_RUNNER = "SUB_FLUSH_RUNNER"; - private boolean _nolocal; + private boolean _noLocal; private final AtomicBoolean _overfull = new AtomicBoolean(false); private boolean _deleteOnNoConsumers; @@ -177,20 +176,15 @@ public class SimpleAMQQueue implements AMQQueue, /** the maximum delivery count for each message on this queue or 0 if maximum delivery count is not to be enforced. */ private int _maximumDeliveryCount; - private final MessageGroupManager _messageGroupManager; + private final MessageGroupManager _messageGroupManager; - private final Collection _consumerListeners = - new ArrayList(); + private final Collection> _consumerListeners = + new ArrayList>(); private AMQQueue.NotificationListener _notificationListener; private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; - public SimpleAMQQueue(UUID id, String queueName, boolean durable, String owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map arguments) - { - this(id, queueName, durable, owner, autoDelete, exclusive, virtualHost, new SimpleQueueEntryList.Factory(), arguments); - } - protected SimpleAMQQueue(UUID id, String name, boolean durable, @@ -198,7 +192,7 @@ public class SimpleAMQQueue implements AMQQueue, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, - QueueEntryListFactory entryListFactory, Map arguments) + QueueEntryListFactory entryListFactory, Map arguments) { if (name == null) @@ -217,7 +211,7 @@ public class SimpleAMQQueue implements AMQQueue, _autoDelete = autoDelete; _exclusive = exclusive; _virtualHost = virtualHost; - _entries = entryListFactory.createQueueEntryList(this); + _entries = entryListFactory.createQueueEntryList((Q)this); _arguments = Collections.synchronizedMap(arguments == null ? new LinkedHashMap() : new LinkedHashMap(arguments)); _id = id; @@ -243,13 +237,13 @@ public class SimpleAMQQueue implements AMQQueue, { Object defaultGroup = arguments.get(Queue.MESSAGE_GROUP_DEFAULT_GROUP); _messageGroupManager = - new DefinedGroupMessageGroupManager(String.valueOf(arguments.get(Queue.MESSAGE_GROUP_KEY)), + new DefinedGroupMessageGroupManager(String.valueOf(arguments.get(Queue.MESSAGE_GROUP_KEY)), defaultGroup == null ? DEFAULT_SHARED_MESSAGE_GROUP : defaultGroup.toString(), this); } else { - _messageGroupManager = new AssignedConsumerMessageGroupManager(String.valueOf(arguments.get( + _messageGroupManager = new AssignedConsumerMessageGroupManager(String.valueOf(arguments.get( Queue.MESSAGE_GROUP_KEY)), DEFAULT_MAX_GROUPS); } } @@ -281,21 +275,20 @@ public class SimpleAMQQueue implements AMQQueue, } catch (RejectedExecutionException ree) { - if (_stopped.get()) - { - // Ignore - SubFlusherRunner or QueueRunner submitted execution as queue was being stopped. - } - else + // Ignore - SubFlusherRunner or QueueRunner submitted execution as queue was being stopped. + if(!_stopped.get()) { _logger.error("Unexpected rejected execution", ree); throw ree; + } + } } public void setNoLocal(boolean nolocal) { - _nolocal = nolocal; + _noLocal = nolocal; } public UUID getId() @@ -384,7 +377,7 @@ public class SimpleAMQQueue implements AMQQueue, @Override - public synchronized QueueConsumer addConsumer(final ConsumerTarget target, + public synchronized QueueConsumer addConsumer(final T target, final FilterManager filters, final Class messageClass, final String consumerName, @@ -412,10 +405,10 @@ public class SimpleAMQQueue implements AMQQueue, throw new ExistingConsumerPreventsExclusive(); } - QueueConsumer consumer = new QueueConsumer(filters, messageClass, - optionSet.contains(Consumer.Option.ACQUIRES), - optionSet.contains(Consumer.Option.SEES_REQUEUES), - consumerName, optionSet.contains(Consumer.Option.TRANSIENT), target); + QueueConsumer consumer = new QueueConsumer(filters, messageClass, + optionSet.contains(Consumer.Option.ACQUIRES), + optionSet.contains(Consumer.Option.SEES_REQUEUES), + consumerName, optionSet.contains(Consumer.Option.TRANSIENT), target); target.consumerAdded(consumer); @@ -430,21 +423,21 @@ public class SimpleAMQQueue implements AMQQueue, } consumer.setStateListener(this); - consumer.setQueueContext(new QueueContext(_entries.getHead())); + consumer.setQueueContext(new QueueContext(_entries.getHead())); if (!isDeleted()) { - consumer.setQueue(this, exclusive); - if(_nolocal) + consumer.setQueue((Q)this, exclusive); + if(_noLocal) { - consumer.setNoLocal(_nolocal); + consumer.setNoLocal(true); } synchronized (_consumerListeners) { - for(ConsumerRegistrationListener listener : _consumerListeners) + for(ConsumerRegistrationListener listener : _consumerListeners) { - listener.consumerAdded(this, consumer); + listener.consumerAdded((Q)this, consumer); } } @@ -466,7 +459,7 @@ public class SimpleAMQQueue implements AMQQueue, } - synchronized void unregisterConsumer(final QueueConsumer consumer) throws AMQException + synchronized void unregisterConsumer(final QueueConsumer consumer) throws AMQException { if (consumer == null) { @@ -494,9 +487,9 @@ public class SimpleAMQQueue implements AMQQueue, synchronized (_consumerListeners) { - for(ConsumerRegistrationListener listener : _consumerListeners) + for(ConsumerRegistrationListener listener : _consumerListeners) { - listener.consumerRemoved(this, consumer); + listener.consumerRemoved((Q)this, consumer); } } @@ -519,10 +512,10 @@ public class SimpleAMQQueue implements AMQQueue, } - public Collection getConsumers() + public Collection> getConsumers() { - List consumers = new ArrayList(); - QueueConsumerList.ConsumerNodeIterator iter = _consumerList.iterator(); + List> consumers = new ArrayList>(); + QueueConsumerList.ConsumerNodeIterator iter = _consumerList.iterator(); while(iter.advance()) { consumers.add(iter.getNode().getConsumer()); @@ -531,7 +524,7 @@ public class SimpleAMQQueue implements AMQQueue, } - public void addConsumerRegistrationListener(final ConsumerRegistrationListener listener) + public void addConsumerRegistrationListener(final ConsumerRegistrationListener listener) { synchronized (_consumerListeners) { @@ -539,7 +532,7 @@ public class SimpleAMQQueue implements AMQQueue, } } - public void removeConsumerRegistrationListener(final ConsumerRegistrationListener listener) + public void removeConsumerRegistrationListener(final ConsumerRegistrationListener listener) { synchronized (_consumerListeners) { @@ -547,9 +540,9 @@ public class SimpleAMQQueue implements AMQQueue, } } - public void resetSubPointersForGroups(QueueConsumer consumer, boolean clearAssignments) + public void resetSubPointersForGroups(QueueConsumer consumer, boolean clearAssignments) { - QueueEntry entry = _messageGroupManager.findEarliestAssignedAvailableEntry(consumer); + E entry = _messageGroupManager.findEarliestAssignedAvailableEntry(consumer); if(clearAssignments) { _messageGroupManager.clearAssignments(consumer); @@ -557,11 +550,11 @@ public class SimpleAMQQueue implements AMQQueue, if(entry != null) { - QueueConsumerList.ConsumerNodeIterator subscriberIter = _consumerList.iterator(); + QueueConsumerList.ConsumerNodeIterator subscriberIter = _consumerList.iterator(); // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards while (subscriberIter.advance()) { - QueueConsumer sub = subscriberIter.getNode().getConsumer(); + QueueConsumer sub = subscriberIter.getNode().getConsumer(); // we don't make browsers send the same stuff twice if (sub.seesRequeues()) @@ -599,11 +592,6 @@ public class SimpleAMQQueue implements AMQQueue, } } - public int getBindingCountHigh() - { - return _bindingCountHigh.get(); - } - public void removeBinding(final Binding binding) { _bindings.remove(binding); @@ -626,7 +614,7 @@ public class SimpleAMQQueue implements AMQQueue, // ------ Enqueue / Dequeue - public void enqueue(ServerMessage message, Action> action) throws AMQException + public void enqueue(ServerMessage message, Action>> action) throws AMQException { incrementQueueCount(); incrementQueueSize(message); @@ -634,8 +622,8 @@ public class SimpleAMQQueue implements AMQQueue, _totalMessagesReceived.incrementAndGet(); - QueueEntry entry; - final QueueConsumer exclusiveSub = _exclusiveSubscriber; + E entry; + final QueueConsumer exclusiveSub = _exclusiveSubscriber; entry = _entries.add(message); if(action != null || (exclusiveSub == null && _queueRunner.isIdle())) @@ -645,8 +633,8 @@ public class SimpleAMQQueue implements AMQQueue, iterate over consumers and if any is at the end of the queue and can deliver this message, then deliver the message */ - QueueConsumerList.ConsumerNode node = _consumerList.getMarkedNode(); - QueueConsumerList.ConsumerNode nextNode = node.findNext(); + QueueConsumerList.ConsumerNode node = _consumerList.getMarkedNode(); + QueueConsumerList.ConsumerNode nextNode = node.findNext(); if (nextNode == null) { nextNode = _consumerList.getHead().findNext(); @@ -682,7 +670,7 @@ public class SimpleAMQQueue implements AMQQueue, else { // if consumer at end, and active, offer - QueueConsumer sub = nextNode.getConsumer(); + QueueConsumer sub = nextNode.getConsumer(); deliverToConsumer(sub, entry); } nextNode = nextNode.findNext(); @@ -714,7 +702,7 @@ public class SimpleAMQQueue implements AMQQueue, } - private void deliverToConsumer(final QueueConsumer sub, final QueueEntry entry) + private void deliverToConsumer(final QueueConsumer sub, final E entry) throws AMQException { @@ -746,7 +734,7 @@ public class SimpleAMQQueue implements AMQQueue, } } - private boolean assign(final QueueConsumer sub, final QueueEntry entry) + private boolean assign(final QueueConsumer sub, final E entry) { if(_messageGroupManager == null) { @@ -760,7 +748,7 @@ public class SimpleAMQQueue implements AMQQueue, } } - private boolean mightAssign(final QueueConsumer sub, final QueueEntry entry) + private boolean mightAssign(final QueueConsumer sub, final E entry) { if(_messageGroupManager == null || !sub.acquires()) { @@ -770,7 +758,7 @@ public class SimpleAMQQueue implements AMQQueue, return (assigned == null) || (assigned == sub); } - protected void checkConsumersNotAheadOfDelivery(final QueueEntry entry) + protected void checkConsumersNotAheadOfDelivery(final E entry) { // This method is only required for queues which mess with ordering // Simple Queues don't :-) @@ -804,7 +792,7 @@ public class SimpleAMQQueue implements AMQQueue, getAtomicQueueCount().incrementAndGet(); } - private void deliverMessage(final QueueConsumer sub, final QueueEntry entry, boolean batch) + private void deliverMessage(final QueueConsumer sub, final E entry, boolean batch) throws AMQException { setLastSeenEntry(sub, entry); @@ -815,18 +803,18 @@ public class SimpleAMQQueue implements AMQQueue, sub.send(entry, batch); } - private boolean consumerReadyAndHasInterest(final QueueConsumer sub, final QueueEntry entry) throws AMQException + private boolean consumerReadyAndHasInterest(final QueueConsumer sub, final E entry) throws AMQException { return sub.hasInterest(entry) && (getNextAvailableEntry(sub) == entry); } - private void setLastSeenEntry(final QueueConsumer sub, final QueueEntry entry) + private void setLastSeenEntry(final QueueConsumer sub, final E entry) { - QueueContext subContext = sub.getQueueContext(); + QueueContext subContext = sub.getQueueContext(); if (subContext != null) { - QueueEntry releasedEntry = subContext.getReleasedEntry(); + E releasedEntry = subContext.getReleasedEntry(); QueueContext._lastSeenUpdater.set(subContext, entry); if(releasedEntry == entry) @@ -836,13 +824,13 @@ public class SimpleAMQQueue implements AMQQueue, } } - private void updateSubRequeueEntry(final QueueConsumer sub, final QueueEntry entry) + private void updateSubRequeueEntry(final QueueConsumer sub, final E entry) { - QueueContext subContext = sub.getQueueContext(); + QueueContext subContext = sub.getQueueContext(); if(subContext != null) { - QueueEntry oldEntry; + E oldEntry; while((oldEntry = subContext.getReleasedEntry()) == null || oldEntry.compareTo(entry) > 0) { @@ -854,13 +842,13 @@ public class SimpleAMQQueue implements AMQQueue, } } - public void requeue(QueueEntry entry) + public void requeue(E entry) { - QueueConsumerList.ConsumerNodeIterator subscriberIter = _consumerList.iterator(); + QueueConsumerList.ConsumerNodeIterator subscriberIter = _consumerList.iterator(); // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards while (subscriberIter.advance() && entry.isAvailable()) { - QueueConsumer sub = subscriberIter.getNode().getConsumer(); + QueueConsumer sub = subscriberIter.getNode().getConsumer(); // we don't make browsers send the same stuff twice if (sub.seesRequeues()) @@ -873,7 +861,8 @@ public class SimpleAMQQueue implements AMQQueue, } - public void dequeue(QueueEntry entry, Consumer sub) + @Override + public void dequeue(E entry) { decrementQueueCount(); decrementQueueSize(entry); @@ -886,7 +875,7 @@ public class SimpleAMQQueue implements AMQQueue, } - private void decrementQueueSize(final QueueEntry entry) + private void decrementQueueSize(final E entry) { final ServerMessage message = entry.getMessage(); long size = message.getSize(); @@ -905,7 +894,7 @@ public class SimpleAMQQueue implements AMQQueue, _dequeueCount.incrementAndGet(); } - public boolean resend(final QueueEntry entry, final Consumer consumer) throws AMQException + public boolean resend(final E entry, final QueueConsumer consumer) throws AMQException { /* TODO : This is wrong as the consumer may be suspended, we should instead change the state of the message entry to resend and move back the consumer pointer. */ @@ -915,7 +904,7 @@ public class SimpleAMQQueue implements AMQQueue, { if (!consumer.isClosed()) { - deliverMessage((QueueConsumer) consumer, entry, false); + deliverMessage(consumer, entry, false); return true; } else @@ -981,11 +970,11 @@ public class SimpleAMQQueue implements AMQQueue, public long getOldestMessageArrivalTime() { - QueueEntry entry = getOldestQueueEntry(); + E entry = getOldestQueueEntry(); return entry == null ? Long.MAX_VALUE : entry.getMessage().getArrivalTime(); } - protected QueueEntry getOldestQueueEntry() + protected E getOldestQueueEntry() { return _entries.next(_entries.getHead()); } @@ -995,13 +984,13 @@ public class SimpleAMQQueue implements AMQQueue, return _deleted.get(); } - public List getMessagesOnTheQueue() + public List getMessagesOnTheQueue() { - ArrayList entryList = new ArrayList(); - QueueEntryIterator queueListIterator = _entries.iterator(); + ArrayList entryList = new ArrayList(); + QueueEntryIterator> queueListIterator = _entries.iterator(); while (queueListIterator.advance()) { - QueueEntry node = queueListIterator.getNode(); + E node = queueListIterator.getNode(); if (node != null && !node.isDeleted()) { entryList.add(node); @@ -1011,7 +1000,7 @@ public class SimpleAMQQueue implements AMQQueue, } - public void stateChanged(QueueConsumer sub, QueueConsumer.State oldState, QueueConsumer.State newState) + public void stateChanged(QueueConsumer sub, QueueConsumer.State oldState, QueueConsumer.State newState) { if (oldState == QueueConsumer.State.ACTIVE && newState != QueueConsumer.State.ACTIVE) { @@ -1029,7 +1018,7 @@ public class SimpleAMQQueue implements AMQQueue, } } - public int compareTo(final AMQQueue o) + public int compareTo(final Q o) { return _name.compareTo(o.getName()); } @@ -1049,7 +1038,7 @@ public class SimpleAMQQueue implements AMQQueue, return _exclusiveSubscriber != null; } - private void setExclusiveSubscriber(QueueConsumer exclusiveSubscriber) + private void setExclusiveSubscriber(QueueConsumer exclusiveSubscriber) { _exclusiveSubscriber = exclusiveSubscriber; } @@ -1060,32 +1049,32 @@ public class SimpleAMQQueue implements AMQQueue, } /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ - protected QueueEntryList getEntries() + protected L getEntries() { return _entries; } - protected QueueConsumerList getConsumerList() + protected QueueConsumerList getConsumerList() { return _consumerList; } - public static interface QueueEntryFilter + public static interface QueueEntryFilter { - public boolean accept(QueueEntry entry); + public boolean accept(E entry); public boolean filterComplete(); } - public List getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) + public List getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) { - return getMessagesOnTheQueue(new QueueEntryFilter() + return getMessagesOnTheQueue(new QueueEntryFilter() { - public boolean accept(QueueEntry entry) + public boolean accept(E entry) { final long messageId = entry.getMessage().getMessageNumber(); return messageId >= fromMessageId && messageId <= toMessageId; @@ -1098,13 +1087,13 @@ public class SimpleAMQQueue implements AMQQueue, }); } - public QueueEntry getMessageOnTheQueue(final long messageId) + public E getMessageOnTheQueue(final long messageId) { - List entries = getMessagesOnTheQueue(new QueueEntryFilter() + List entries = getMessagesOnTheQueue(new QueueEntryFilter() { private boolean _complete; - public boolean accept(QueueEntry entry) + public boolean accept(E entry) { _complete = entry.getMessage().getMessageNumber() == messageId; return _complete; @@ -1118,13 +1107,13 @@ public class SimpleAMQQueue implements AMQQueue, return entries.isEmpty() ? null : entries.get(0); } - public List getMessagesOnTheQueue(QueueEntryFilter filter) + public List getMessagesOnTheQueue(QueueEntryFilter filter) { - ArrayList entryList = new ArrayList(); - QueueEntryIterator queueListIterator = _entries.iterator(); + ArrayList entryList = new ArrayList(); + QueueEntryIterator> queueListIterator = _entries.iterator(); while (queueListIterator.advance() && !filter.filterComplete()) { - QueueEntry node = queueListIterator.getNode(); + E node = queueListIterator.getNode(); if (!node.isDeleted() && filter.accept(node)) { entryList.add(node); @@ -1134,13 +1123,13 @@ public class SimpleAMQQueue implements AMQQueue, } - public void visit(final QueueEntryVisitor visitor) + public void visit(final QueueEntryVisitor visitor) { - QueueEntryIterator queueListIterator = _entries.iterator(); + QueueEntryIterator> queueListIterator = _entries.iterator(); while(queueListIterator.advance()) { - QueueEntry node = queueListIterator.getNode(); + E node = queueListIterator.getNode(); if(!node.isDeleted()) { @@ -1157,17 +1146,17 @@ public class SimpleAMQQueue implements AMQQueue, * * 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 + * @param fromPosition first message position + * @param toPosition last message position + * @return list of messages */ - public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition) + public List getMessagesRangeOnTheQueue(final long fromPosition, final long toPosition) { - return getMessagesOnTheQueue(new QueueEntryFilter() + return getMessagesOnTheQueue(new QueueEntryFilter() { private long position = 0; - public boolean accept(QueueEntry entry) + public boolean accept(E entry) { position++; return (position >= fromPosition) && (position <= toPosition); @@ -1196,12 +1185,12 @@ public class SimpleAMQQueue implements AMQQueue, // TODO - now only used by the tests public void deleteMessageFromTop() { - QueueEntryIterator queueListIterator = _entries.iterator(); + QueueEntryIterator> queueListIterator = _entries.iterator(); boolean noDeletes = true; while (noDeletes && queueListIterator.advance()) { - QueueEntry node = queueListIterator.getNode(); + E node = queueListIterator.getNode(); if (node.acquire()) { dequeueEntry(node); @@ -1224,14 +1213,14 @@ public class SimpleAMQQueue implements AMQQueue, throw new AMQSecurityException("Permission denied: queue " + getName()); } - QueueEntryIterator queueListIterator = _entries.iterator(); + QueueEntryIterator> queueListIterator = _entries.iterator(); long count = 0; ServerTransaction txn = new LocalTransaction(getVirtualHost().getMessageStore()); while (queueListIterator.advance()) { - QueueEntry node = queueListIterator.getNode(); + E node = queueListIterator.getNode(); if (node.acquire()) { dequeueEntry(node, txn); @@ -1248,13 +1237,13 @@ public class SimpleAMQQueue implements AMQQueue, return count; } - private void dequeueEntry(final QueueEntry node) + private void dequeueEntry(final E node) { ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getMessageStore()); dequeueEntry(node, txn); } - private void dequeueEntry(final QueueEntry node, ServerTransaction txn) + private void dequeueEntry(final E node, ServerTransaction txn) { txn.dequeue(this, node.getMessage(), new ServerTransaction.Action() @@ -1283,7 +1272,7 @@ public class SimpleAMQQueue implements AMQQueue, } // TODO list all thrown exceptions - public int delete() throws AMQSecurityException, AMQException + public int delete() throws AMQException { // Check access if (!_virtualHost.getSecurityManager().authoriseDelete(this)) @@ -1313,10 +1302,10 @@ public class SimpleAMQQueue implements AMQQueue, } - List entries = getMessagesOnTheQueue(new QueueEntryFilter() + List entries = getMessagesOnTheQueue(new QueueEntryFilter() { - public boolean accept(QueueEntry entry) + public boolean accept(E entry) { return entry.acquire(); } @@ -1330,7 +1319,7 @@ public class SimpleAMQQueue implements AMQQueue, ServerTransaction txn = new LocalTransaction(getVirtualHost().getMessageStore()); - for(final QueueEntry entry : entries) + for(final E entry : entries) { // TODO log requeues with a post enqueue action int requeues = entry.routeToAlternate(null, txn); @@ -1435,7 +1424,7 @@ public class SimpleAMQQueue implements AMQQueue, } - public void deliverAsync(QueueConsumer sub) + public void deliverAsync(QueueConsumer sub) { if(_exclusiveSubscriber == null) { @@ -1449,7 +1438,7 @@ public class SimpleAMQQueue implements AMQQueue, } - void flushConsumer(QueueConsumer sub) throws AMQException + void flushConsumer(QueueConsumer sub) throws AMQException { // Access control if (!getVirtualHost().getSecurityManager().authoriseConsume(this)) @@ -1459,7 +1448,7 @@ public class SimpleAMQQueue implements AMQQueue, flushConsumer(sub, Long.MAX_VALUE); } - boolean flushConsumer(QueueConsumer sub, long iterations) throws AMQException + boolean flushConsumer(QueueConsumer sub, long iterations) throws AMQException { boolean atTail = false; final boolean keepSendLockHeld = iterations <= SimpleAMQQueue.MAX_ASYNC_DELIVERIES; @@ -1480,8 +1469,8 @@ public class SimpleAMQQueue implements AMQQueue, sub.getSendLock(); } - atTail = attemptDelivery((QueueConsumer)sub, true); - if (atTail && getNextAvailableEntry((QueueConsumer)sub) == null) + atTail = attemptDelivery(sub, true); + if (atTail && getNextAvailableEntry(sub) == null) { queueEmpty = true; } @@ -1532,12 +1521,12 @@ public class SimpleAMQQueue implements AMQQueue, * Looks up the next node for the consumer and attempts to deliver it. * * - * @param sub - * @param batch + * @param sub the consumer + * @param batch true if processing can be batched * @return true if we have completed all possible deliveries for this sub. * @throws AMQException */ - private boolean attemptDelivery(QueueConsumer sub, boolean batch) throws AMQException + private boolean attemptDelivery(QueueConsumer sub, boolean batch) throws AMQException { boolean atTail = false; @@ -1545,7 +1534,7 @@ public class SimpleAMQQueue implements AMQQueue, if (subActive) { - QueueEntry node = getNextAvailableEntry(sub); + E node = getNextAvailableEntry(sub); if (node != null && node.isAvailable()) { @@ -1582,11 +1571,11 @@ public class SimpleAMQQueue implements AMQQueue, protected void advanceAllConsumers() throws AMQException { - QueueConsumerList.ConsumerNodeIterator consumerNodeIterator = _consumerList.iterator(); + QueueConsumerList.ConsumerNodeIterator consumerNodeIterator = _consumerList.iterator(); while (consumerNodeIterator.advance()) { - QueueConsumerList.ConsumerNode subNode = consumerNodeIterator.getNode(); - QueueConsumer sub = subNode.getConsumer(); + QueueConsumerList.ConsumerNode subNode = consumerNodeIterator.getNode(); + QueueConsumer sub = subNode.getConsumer(); if(sub.acquires()) { getNextAvailableEntry(sub); @@ -1598,16 +1587,16 @@ public class SimpleAMQQueue implements AMQQueue, } } - private QueueEntry getNextAvailableEntry(final QueueConsumer sub) + private E getNextAvailableEntry(final QueueConsumer sub) throws AMQException { - QueueContext context = sub.getQueueContext(); + QueueContext context = sub.getQueueContext(); if(context != null) { - QueueEntry lastSeen = context.getLastSeenEntry(); - QueueEntry releasedNode = context.getReleasedEntry(); + E lastSeen = context.getLastSeenEntry(); + E releasedNode = context.getReleasedEntry(); - QueueEntry node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen); + E node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen); boolean expired = false; while (node != null && (!node.isAvailable() || (expired = node.expired()) || !sub.hasInterest(node) || @@ -1639,12 +1628,12 @@ public class SimpleAMQQueue implements AMQQueue, } } - public boolean isEntryAheadOfConsumer(QueueEntry entry, QueueConsumer sub) + public boolean isEntryAheadOfConsumer(E entry, QueueConsumer sub) { - QueueContext context = sub.getQueueContext(); + QueueContext context = sub.getQueueContext(); if(context != null) { - QueueEntry releasedNode = context.getReleasedEntry(); + E releasedNode = context.getReleasedEntry(); return releasedNode != null && releasedNode.compareTo(entry) < 0; } else @@ -1681,7 +1670,7 @@ public class SimpleAMQQueue implements AMQQueue, */ public long processQueue(QueueRunner runner) throws AMQException { - long stateChangeCount = Long.MIN_VALUE; + long stateChangeCount; long previousStateChangeCount = Long.MIN_VALUE; long rVal = Long.MIN_VALUE; boolean deliveryIncomplete = true; @@ -1716,11 +1705,11 @@ public class SimpleAMQQueue implements AMQQueue, boolean allConsumersDone = true; boolean consumerDone; - QueueConsumerList.ConsumerNodeIterator consumerNodeIterator = _consumerList.iterator(); + QueueConsumerList.ConsumerNodeIterator consumerNodeIterator = _consumerList.iterator(); //iterate over the subscribers and try to advance their pointer while (consumerNodeIterator.advance()) { - QueueConsumer sub = consumerNodeIterator.getNode().getConsumer(); + QueueConsumer sub = consumerNodeIterator.getNode().getConsumer(); sub.getSendLock(); try @@ -1802,11 +1791,11 @@ public class SimpleAMQQueue implements AMQQueue, public void checkMessageStatus() throws AMQException { - QueueEntryIterator queueListIterator = _entries.iterator(); + QueueEntryIterator> queueListIterator = _entries.iterator(); while (queueListIterator.advance()) { - QueueEntry node = queueListIterator.getNode(); + E node = queueListIterator.getNode(); // Only process nodes that are not currently deleted and not dequeued if (!node.isDeleted()) { @@ -1953,12 +1942,12 @@ public class SimpleAMQQueue implements AMQQueue, return _notificationChecks; } - private final class QueueEntryListener implements StateChangeListener, QueueEntry.State> + private final class QueueEntryListener implements StateChangeListener { - private final QueueConsumer _sub; + private final QueueConsumer _sub; - public QueueEntryListener(final QueueConsumer sub) + public QueueEntryListener(final QueueConsumer sub) { _sub = sub; } @@ -1974,7 +1963,7 @@ public class SimpleAMQQueue implements AMQQueue, return System.identityHashCode(_sub); } - public void stateChanged(MessageInstance entry, QueueEntry.State oldSate, QueueEntry.State newState) + public void stateChanged(E entry, QueueEntry.State oldSate, QueueEntry.State newState) { entry.removeStateChangeListener(this); deliverAsync(_sub); @@ -2082,13 +2071,13 @@ public class SimpleAMQQueue implements AMQQueue, return _unackedMsgBytes.get(); } - public void decrementUnackedMsgCount(QueueEntry queueEntry) + public void decrementUnackedMsgCount(E queueEntry) { _unackedMsgCount.decrementAndGet(); _unackedMsgBytes.addAndGet(-queueEntry.getSize()); } - private void incrementUnackedMsgCount(QueueEntry entry) + private void incrementUnackedMsgCount(E entry) { _unackedMsgCount.incrementAndGet(); _unackedMsgBytes.addAndGet(entry.getSize()); @@ -2159,10 +2148,10 @@ public class SimpleAMQQueue implements AMQQueue, return (String) _arguments.get(Queue.DESCRIPTION); } - public final int send(final ServerMessage message, + public final > int send(final M message, final InstanceProperties instanceProperties, final ServerTransaction txn, - final Action> postEnqueueAction) + final Action> postEnqueueAction) { txn.enqueue(this,message, new ServerTransaction.Action() { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java deleted file mode 100644 index 251a1f55ed..0000000000 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.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.queue; - -import org.apache.qpid.server.message.ServerMessage; - -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - -public class SimpleQueueEntryImpl extends QueueEntryImpl -{ - static final AtomicReferenceFieldUpdater - _nextUpdater = - AtomicReferenceFieldUpdater.newUpdater - (SimpleQueueEntryImpl.class, SimpleQueueEntryImpl.class, "_next"); - - private volatile SimpleQueueEntryImpl _next; - - public SimpleQueueEntryImpl(SimpleQueueEntryList queueEntryList) - { - super(queueEntryList); - } - - public SimpleQueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId) - { - super(queueEntryList, message, entryId); - } - - public SimpleQueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message) - { - super(queueEntryList, message); - } - - public SimpleQueueEntryImpl getNextNode() - { - return _next; - } - - public SimpleQueueEntryImpl getNextValidEntry() - { - - SimpleQueueEntryImpl next = getNextNode(); - while(next != null && next.isDeleted()) - { - - final SimpleQueueEntryImpl newNext = next.getNextNode(); - if(newNext != null) - { - SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext); - next = getNextNode(); - } - else - { - next = null; - } - - } - return next; - } - -} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index 101771c7cc..b6954e0696 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -1,205 +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. -* -*/ + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either 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 java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - -public class SimpleQueueEntryList implements QueueEntryList +public interface SimpleQueueEntryList, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> extends QueueEntryList> { - - private final SimpleQueueEntryImpl _head; - - private volatile SimpleQueueEntryImpl _tail; - - static final AtomicReferenceFieldUpdater - _tailUpdater = - AtomicReferenceFieldUpdater.newUpdater - (SimpleQueueEntryList.class, SimpleQueueEntryImpl.class, "_tail"); - - - private final AMQQueue _queue; - - static final AtomicReferenceFieldUpdater - _nextUpdater = SimpleQueueEntryImpl._nextUpdater; - - private AtomicLong _scavenges = new AtomicLong(0L); - private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50); - private final AtomicReference _unscavengedHWM = new AtomicReference(); - - - public SimpleQueueEntryList(AMQQueue queue) - { - _queue = queue; - _head = new SimpleQueueEntryImpl(this); - _tail = _head; - } - - void scavenge() - { - SimpleQueueEntryImpl hwm = _unscavengedHWM.getAndSet(null); - SimpleQueueEntryImpl next = _head.getNextValidEntry(); - - if(hwm != null) - { - while (next != null && hwm.compareTo(next)>0) - { - next = next.getNextValidEntry(); - } - } - } - - - public AMQQueue getQueue() - { - return _queue; - } - - - public SimpleQueueEntryImpl add(ServerMessage message) - { - SimpleQueueEntryImpl node = createQueueEntry(message); - for (;;) - { - SimpleQueueEntryImpl tail = _tail; - SimpleQueueEntryImpl next = tail.getNextNode(); - 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); - } - } - } - } - - protected SimpleQueueEntryImpl createQueueEntry(ServerMessage message) - { - return new SimpleQueueEntryImpl(this, message); - } - - public SimpleQueueEntryImpl next(SimpleQueueEntryImpl node) - { - return node.getNextValidEntry(); - } - - public static class QueueEntryIteratorImpl implements QueueEntryIterator - { - private SimpleQueueEntryImpl _lastNode; - - QueueEntryIteratorImpl(SimpleQueueEntryImpl startNode) - { - _lastNode = startNode; - } - - public boolean atTail() - { - return _lastNode.getNextValidEntry() == null; - } - - public SimpleQueueEntryImpl getNode() - { - return _lastNode; - } - - public boolean advance() - { - SimpleQueueEntryImpl nextValidNode = _lastNode.getNextValidEntry(); - - if(nextValidNode != null) - { - _lastNode = nextValidNode; - } - - return nextValidNode != null; - } - } - - public QueueEntryIteratorImpl iterator() - { - return new QueueEntryIteratorImpl(_head); - } - - - public SimpleQueueEntryImpl getHead() - { - return _head; - } - - public void entryDeleted(SimpleQueueEntryImpl queueEntry) - { - SimpleQueueEntryImpl next = _head.getNextNode(); - SimpleQueueEntryImpl newNext = _head.getNextValidEntry(); - - // the head of the queue has not been deleted, hence the deletion must have been mid queue. - if (next == newNext) - { - SimpleQueueEntryImpl unscavengedHWM = _unscavengedHWM.get(); - while(unscavengedHWM == null || unscavengedHWM.compareTo(queueEntry)<0) - { - _unscavengedHWM.compareAndSet(unscavengedHWM, queueEntry); - unscavengedHWM = _unscavengedHWM.get(); - } - if (_scavenges.incrementAndGet() > _scavengeCount) - { - _scavenges.set(0L); - scavenge(); - } - } - else - { - SimpleQueueEntryImpl unscavengedHWM = _unscavengedHWM.get(); - if(unscavengedHWM != null && (next == null || unscavengedHWM.compareTo(next) < 0)) - { - _unscavengedHWM.compareAndSet(unscavengedHWM, null); - } - } - } - - public int getPriorities() - { - return 0; - } - - static class Factory implements QueueEntryListFactory - { - - public SimpleQueueEntryList createQueueEntryList(AMQQueue queue) - { - return new SimpleQueueEntryList(queue); - } - } - - } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueue.java index cad1aa6d4f..2cae18f3ec 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueue.java @@ -29,7 +29,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; import java.util.UUID; -public class SortedQueue extends OutOfOrderQueue +public class SortedQueue extends OutOfOrderQueue { //Lock object to synchronize enqueue. Used instead of the object //monitor to prevent lock order issues with consumer sendLocks @@ -40,18 +40,34 @@ public class SortedQueue extends OutOfOrderQueue protected SortedQueue(UUID id, final String name, final boolean durable, final String owner, final boolean autoDelete, final boolean exclusive, final VirtualHost virtualHost, Map arguments, String sortedPropertyName) + { + this(id, name, durable, owner, autoDelete, exclusive, + virtualHost, arguments, sortedPropertyName, new SortedQueueEntryListFactory(sortedPropertyName)); + } + + + protected SortedQueue(UUID id, final String name, + final boolean durable, final String owner, final boolean autoDelete, + final boolean exclusive, final VirtualHost virtualHost, + Map arguments, + String sortedPropertyName, + QueueEntryListFactory factory) { super(id, name, durable, owner, autoDelete, exclusive, - virtualHost, new SortedQueueEntryListFactory(sortedPropertyName), arguments); + virtualHost, factory, arguments); this._sortedPropertyName = sortedPropertyName; } + public String getSortedPropertyName() { return _sortedPropertyName; } - public void enqueue(ServerMessage message, Action> action) throws AMQException + @Override + public void enqueue(final ServerMessage message, + final Action>> action) + throws AMQException { synchronized (_sortedQueueLock) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntry.java new file mode 100644 index 0000000000..30d58138fb --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntry.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.queue; + +import org.apache.qpid.server.message.ServerMessage; + +/** + * An implementation of QueueEntryImpl to be used in SortedQueueEntryList. + */ +public class SortedQueueEntry extends QueueEntryImpl +{ + public static enum Colour + { + RED, BLACK + }; + + private volatile SortedQueueEntry _next; + private SortedQueueEntry _prev; + private String _key; + + private Colour _colour = Colour.BLACK; + private SortedQueueEntry _parent; + private SortedQueueEntry _left; + private SortedQueueEntry _right; + + public SortedQueueEntry(final SortedQueueEntryList queueEntryList) + { + super(queueEntryList); + } + + public SortedQueueEntry(final SortedQueueEntryList queueEntryList, + final ServerMessage message, final long entryId) + { + super(queueEntryList, message, entryId); + } + + @Override + public int compareTo(final SortedQueueEntry o) + { + final String otherKey = o._key; + final int compare = _key == null ? (otherKey == null ? 0 : -1) : otherKey == null ? 1 : _key.compareTo(otherKey); + return compare == 0 ? super.compareTo(o) : compare; + } + + public Colour getColour() + { + return _colour; + } + + public String getKey() + { + return _key; + } + + public SortedQueueEntry getLeft() + { + return _left; + } + + public SortedQueueEntry getNextNode() + { + return _next; + } + + @Override + public SortedQueueEntry getNextValidEntry() + { + return getNextNode(); + } + + public SortedQueueEntry getParent() + { + return _parent; + } + + public SortedQueueEntry getPrev() + { + return _prev; + } + + public SortedQueueEntry getRight() + { + return _right; + } + + public void setColour(final Colour colour) + { + _colour = colour; + } + + public void setKey(final String key) + { + _key = key; + } + + public void setLeft(final SortedQueueEntry left) + { + _left = left; + } + + public void setNext(final SortedQueueEntry next) + { + _next = next; + } + + public void setParent(final SortedQueueEntry parent) + { + _parent = parent; + } + + public void setPrev(final SortedQueueEntry prev) + { + _prev = prev; + } + + public void setRight(final SortedQueueEntry right) + { + _right = right; + } + + @Override + public String toString() + { + return "(" + (_colour == Colour.RED ? "Red," : "Black,") + _key + ")"; + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java deleted file mode 100644 index 1052adbe67..0000000000 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.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.queue; - -import org.apache.qpid.server.message.ServerMessage; - -/** - * An implementation of QueueEntryImpl to be used in SortedQueueEntryList. - */ -public class SortedQueueEntryImpl extends QueueEntryImpl -{ - public static enum Colour - { - RED, BLACK - }; - - private volatile SortedQueueEntryImpl _next; - private SortedQueueEntryImpl _prev; - private String _key; - - private Colour _colour = Colour.BLACK; - private SortedQueueEntryImpl _parent; - private SortedQueueEntryImpl _left; - private SortedQueueEntryImpl _right; - - public SortedQueueEntryImpl(final SortedQueueEntryList queueEntryList) - { - super(queueEntryList); - } - - public SortedQueueEntryImpl(final SortedQueueEntryList queueEntryList, - final ServerMessage message, final long entryId) - { - super(queueEntryList, message, entryId); - } - - @Override - public int compareTo(final QueueEntry o) - { - final String otherKey = ((SortedQueueEntryImpl) o)._key; - final int compare = _key == null ? (otherKey == null ? 0 : -1) : otherKey == null ? 1 : _key.compareTo(otherKey); - return compare == 0 ? super.compareTo(o) : compare; - } - - public Colour getColour() - { - return _colour; - } - - public String getKey() - { - return _key; - } - - public SortedQueueEntryImpl getLeft() - { - return _left; - } - - public SortedQueueEntryImpl getNextNode() - { - return _next; - } - - @Override - public SortedQueueEntryImpl getNextValidEntry() - { - return getNextNode(); - } - - public SortedQueueEntryImpl getParent() - { - return _parent; - } - - public SortedQueueEntryImpl getPrev() - { - return _prev; - } - - public SortedQueueEntryImpl getRight() - { - return _right; - } - - public void setColour(final Colour colour) - { - _colour = colour; - } - - public void setKey(final String key) - { - _key = key; - } - - public void setLeft(final SortedQueueEntryImpl left) - { - _left = left; - } - - public void setNext(final SortedQueueEntryImpl next) - { - _next = next; - } - - public void setParent(final SortedQueueEntryImpl parent) - { - _parent = parent; - } - - public void setPrev(final SortedQueueEntryImpl prev) - { - _prev = prev; - } - - public void setRight(final SortedQueueEntryImpl right) - { - _right = right; - } - - @Override - public String toString() - { - return "(" + (_colour == Colour.RED ? "Red," : "Black,") + _key + ")"; - } -} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java index 336ee566eb..05b874cd91 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java @@ -21,7 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour; +import org.apache.qpid.server.queue.SortedQueueEntry.Colour; /** * A sorted implementation of QueueEntryList. @@ -30,28 +30,28 @@ import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour; * ISBN-13: 978-0262033848 * see http://en.wikipedia.org/wiki/Red-black_tree */ -public class SortedQueueEntryList implements QueueEntryList +public class SortedQueueEntryList implements SimpleQueueEntryList { - private final SortedQueueEntryImpl _head; - private SortedQueueEntryImpl _root; + private final SortedQueueEntry _head; + private SortedQueueEntry _root; private long _entryId = Long.MIN_VALUE; private final Object _lock = new Object(); - private final AMQQueue _queue; + private final SortedQueue _queue; private final String _propertyName; - public SortedQueueEntryList(final AMQQueue queue, final String propertyName) + public SortedQueueEntryList(final SortedQueue queue, final String propertyName) { _queue = queue; - _head = new SortedQueueEntryImpl(this); + _head = new SortedQueueEntry(this); _propertyName = propertyName; } - public AMQQueue getQueue() + public SortedQueue getQueue() { return _queue; } - public SortedQueueEntryImpl add(final ServerMessage message) + public SortedQueueEntry add(final ServerMessage message) { synchronized(_lock) { @@ -62,7 +62,7 @@ public class SortedQueueEntryList implements QueueEntryList iterator() + public QueueEntryIterator> iterator() { return new QueueEntryIteratorImpl(_head); } - public SortedQueueEntryImpl getHead() + public SortedQueueEntry getHead() { return _head; } - protected SortedQueueEntryImpl getRoot() + protected SortedQueueEntry getRoot() { return _root; } - public void entryDeleted(final SortedQueueEntryImpl entry) + public void entryDeleted(final SortedQueueEntry entry) { synchronized(_lock) { @@ -336,20 +336,20 @@ public class SortedQueueEntryList implements QueueEntryList + public class QueueEntryIteratorImpl implements QueueEntryIterator> { - private SortedQueueEntryImpl _lastNode; + private SortedQueueEntry _lastNode; - public QueueEntryIteratorImpl(final SortedQueueEntryImpl startNode) + public QueueEntryIteratorImpl(final SortedQueueEntry startNode) { _lastNode = startNode; } @@ -632,7 +632,7 @@ public class SortedQueueEntryList implements QueueEntryList { private final String _propertyName; @@ -30,9 +30,8 @@ public class SortedQueueEntryListFactory implements QueueEntryListFactory } @Override - public QueueEntryList createQueueEntryList(final AMQQueue queue) + public SortedQueueEntryList createQueueEntryList(final SortedQueue queue) { return new SortedQueueEntryList(queue, _propertyName); } - } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueue.java new file mode 100644 index 0000000000..e2ccdc45cf --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueue.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.virtualhost.VirtualHost; + +import java.util.Map; +import java.util.UUID; + +public class StandardQueue extends SimpleAMQQueue +{ + public StandardQueue(final UUID id, + final String name, + final boolean durable, + final String owner, + final boolean autoDelete, + final boolean exclusive, + final VirtualHost virtualHost, + final Map arguments) + { + super(id, name, durable, owner, autoDelete, exclusive, virtualHost, new StandardQueueEntryList.Factory(), arguments); + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntry.java new file mode 100644 index 0000000000..368015e9c0 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntry.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.server.message.ServerMessage; + +public class StandardQueueEntry extends OrderedQueueEntry +{ + protected StandardQueueEntry(final StandardQueueEntryList queueEntryList) + { + super(queueEntryList); + } + + public StandardQueueEntry(final StandardQueueEntryList queueEntryList, + final ServerMessage message, + final long entryId) + { + super(queueEntryList, message, entryId); + } + + public StandardQueueEntry(final StandardQueueEntryList queueEntryList, final ServerMessage message) + { + super(queueEntryList, message); + } + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntryList.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntryList.java new file mode 100644 index 0000000000..11ad04e61c --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/StandardQueueEntryList.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.message.ServerMessage; + +public class StandardQueueEntryList extends OrderedQueueEntryList +{ + + private static final HeadCreator HEAD_CREATOR = new HeadCreator() + { + @Override + public StandardQueueEntry createHead(final StandardQueueEntryList list) + { + return new StandardQueueEntry(list); + } + }; + + public StandardQueueEntryList(final StandardQueue queue) + { + super(queue, HEAD_CREATOR); + } + + + protected StandardQueueEntry createQueueEntry(ServerMessage message) + { + return new StandardQueueEntry(this, message); + } + + static class Factory implements QueueEntryListFactory + { + + public StandardQueueEntryList createQueueEntryList(StandardQueue queue) + { + return new StandardQueueEntryList(queue); + } + } + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/DurableConfigurationStoreHelper.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/DurableConfigurationStoreHelper.java index de7369f5ed..eff9bdf433 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/DurableConfigurationStoreHelper.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/DurableConfigurationStoreHelper.java @@ -47,7 +47,7 @@ public class DurableConfigurationStoreHelper Queue.EXCLUSIVE, Queue.ALTERNATE_EXCHANGE)); - public static void updateQueue(DurableConfigurationStore store, AMQQueue queue) throws AMQStoreException + public static void updateQueue(DurableConfigurationStore store, AMQQueue queue) throws AMQStoreException { Map attributesMap = new LinkedHashMap(); attributesMap.put(Queue.NAME, queue.getName()); @@ -72,7 +72,7 @@ public class DurableConfigurationStoreHelper store.update(queue.getId(), QUEUE, attributesMap); } - public static void createQueue(DurableConfigurationStore store, AMQQueue queue) + public static void createQueue(DurableConfigurationStore store, AMQQueue queue) throws AMQStoreException { Map attributesMap = new HashMap(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java index 9a23e00f90..3d42b07117 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java @@ -105,6 +105,7 @@ public abstract class AbstractVirtualHost implements VirtualHost, IConnectionReg private final DtxRegistry _dtxRegistry; private final AMQQueueFactory _queueFactory; private final SystemNodeRegistry _systemNodeRegistry = new SystemNodeRegistry(); + private final org.apache.qpid.server.model.VirtualHost _model; private volatile State _state = State.INITIALISING; @@ -141,6 +142,7 @@ public abstract class AbstractVirtualHost implements VirtualHost, IConnectionReg _vhostConfig = hostConfig; _name = _vhostConfig.getName(); _dtxRegistry = new DtxRegistry(); + _model = virtualHost; _id = UUIDGenerator.generateVhostUUID(_name); @@ -1001,5 +1003,11 @@ public abstract class AbstractVirtualHost implements VirtualHost, IConnectionReg { return AbstractVirtualHost.this; } + + @Override + public org.apache.qpid.server.model.VirtualHost getVirtualHostModel() + { + return _model; + } } } diff --git a/qpid/java/broker-core/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageMetaDataType b/qpid/java/broker-core/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageMetaDataType new file mode 100644 index 0000000000..a744bfff53 --- /dev/null +++ b/qpid/java/broker-core/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageMetaDataType @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +org.apache.qpid.server.message.internal.InternalMessageMetaDataType diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java index f60f173de9..4dd9831454 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java @@ -27,7 +27,7 @@ import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.queue.AMQPriorityQueue; +import org.apache.qpid.server.queue.PriorityQueue; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.util.BrokerTestHelper; @@ -113,17 +113,17 @@ public class VirtualHostConfigurationTest extends QpidTestCase // Check that atest was a priority queue with 5 priorities AMQQueue atest = vhost.getQueue("atest"); - assertTrue(atest instanceof AMQPriorityQueue); - assertEquals(5, ((AMQPriorityQueue) atest).getPriorities()); + assertTrue(atest instanceof PriorityQueue); + assertEquals(5, ((PriorityQueue) atest).getPriorities()); // Check that ptest was a priority queue with 10 priorities AMQQueue ptest = vhost.getQueue("ptest"); - assertTrue(ptest instanceof AMQPriorityQueue); - assertEquals(10, ((AMQPriorityQueue) ptest).getPriorities()); + assertTrue(ptest instanceof PriorityQueue); + assertEquals(10, ((PriorityQueue) ptest).getPriorities()); // Check that ntest wasn't a priority queue AMQQueue ntest = vhost.getQueue("ntest"); - assertFalse(ntest instanceof AMQPriorityQueue); + assertFalse(ntest instanceof PriorityQueue); } public void testQueueAlerts() throws Exception diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java index ea9d0ac693..8cab2e9058 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java @@ -74,7 +74,7 @@ public class TopicExchangeTest extends QpidTestCase public void testNoRoute() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a*#b", false, null, false, false, + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a*#b", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.*.#.b",queue, _exchange, null)); @@ -86,7 +86,7 @@ public class TopicExchangeTest extends QpidTestCase public void testDirectMatch() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "ab", false, null, false, false, + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "ab", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.b",queue, _exchange, null)); @@ -109,7 +109,7 @@ public class TopicExchangeTest extends QpidTestCase public void testStarMatch() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a*", false, null, false, false, false, null); + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a*", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.*",queue, _exchange, null)); @@ -140,7 +140,7 @@ public class TopicExchangeTest extends QpidTestCase public void testHashMatch() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, false, null); + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.#",queue, _exchange, null)); @@ -191,7 +191,7 @@ public class TopicExchangeTest extends QpidTestCase public void testMidHash() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a", false, null, false, false, + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.*.#.b",queue, _exchange, null)); @@ -217,7 +217,7 @@ public class TopicExchangeTest extends QpidTestCase public void testMatchAfterHash() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.*.#.b.c",queue, _exchange, null)); @@ -256,7 +256,7 @@ public class TopicExchangeTest extends QpidTestCase public void testHashAfterHash() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.*.#.b.c.#.d",queue, _exchange, null)); @@ -278,7 +278,7 @@ public class TopicExchangeTest extends QpidTestCase public void testHashHash() throws AMQException { - AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, + AMQQueue queue = _vhost.createQueue(UUIDGenerator.generateRandomUUID(), "a#", false, null, false, false, false, null); _exchange.registerQueue(new Binding(null, "a.#.*.#.d",queue, _exchange, null)); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java deleted file mode 100644 index ced00dc578..0000000000 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.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.queue; - -import java.util.Collections; -import junit.framework.AssertionFailedError; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.message.AMQMessageHeader; -import org.apache.qpid.server.message.MessageInstance; -import org.apache.qpid.server.message.ServerMessage; - -import java.util.ArrayList; -import java.util.EnumSet; - -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.consumer.Consumer; - -import static org.mockito.Mockito.when; - -public class AMQPriorityQueueTest extends SimpleAMQQueueTest -{ - - @Override - public void setUp() throws Exception - { - setArguments(Collections.singletonMap(Queue.PRIORITIES,(Object)3)); - super.setUp(); - } - - public void testPriorityOrdering() throws AMQException, InterruptedException - { - - // Enqueue messages in order - SimpleAMQQueue queue = getQueue(); - queue.enqueue(createMessage(1L, (byte) 10), null); - queue.enqueue(createMessage(2L, (byte) 4), null); - queue.enqueue(createMessage(3L, (byte) 0), null); - - // Enqueue messages in reverse order - queue.enqueue(createMessage(4L, (byte) 0), null); - queue.enqueue(createMessage(5L, (byte) 4), null); - queue.enqueue(createMessage(6L, (byte) 10), null); - - // Enqueue messages out of order - queue.enqueue(createMessage(7L, (byte) 4), null); - queue.enqueue(createMessage(8L, (byte) 10), null); - queue.enqueue(createMessage(9L, (byte) 0), null); - - // Register subscriber - queue.addConsumer(getConsumer(), null, null, "test", EnumSet.noneOf(Consumer.Option.class)); - Thread.sleep(150); - - ArrayList msgs = getConsumer().getMessages(); - try - { - assertEquals(1L, msgs.get(0).getMessage().getMessageNumber()); - assertEquals(6L, msgs.get(1).getMessage().getMessageNumber()); - assertEquals(8L, msgs.get(2).getMessage().getMessageNumber()); - - assertEquals(2L, msgs.get(3).getMessage().getMessageNumber()); - assertEquals(5L, msgs.get(4).getMessage().getMessageNumber()); - assertEquals(7L, msgs.get(5).getMessage().getMessageNumber()); - - assertEquals(3L, msgs.get(6).getMessage().getMessageNumber()); - assertEquals(4L, msgs.get(7).getMessage().getMessageNumber()); - assertEquals(9L, msgs.get(8).getMessage().getMessageNumber()); - } - catch (AssertionFailedError afe) - { - // Show message order on failure. - int index = 1; - for (MessageInstance qe : msgs) - { - System.err.println(index + ":" + qe.getMessage().getMessageNumber()); - index++; - } - - throw afe; - } - - } - - protected ServerMessage createMessage(Long id, byte i) throws AMQException - { - - ServerMessage msg = super.createMessage(id); - AMQMessageHeader hdr = msg.getMessageHeader(); - when(hdr.getPriority()).thenReturn(i); - return msg; - } - - protected ServerMessage createMessage(Long id) throws AMQException - { - return createMessage(id, (byte) 0); - } - -} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java index bcf54c97a4..febce9ea2e 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java @@ -231,7 +231,7 @@ public class AMQQueueFactoryTest extends QpidTestCase false, attributes); - assertEquals("Queue not a priority queue", AMQPriorityQueue.class, queue.getClass()); + assertEquals("Queue not a priority queue", PriorityQueue.class, queue.getClass()); verifyQueueRegistered("testPriorityQueue"); verifyRegisteredQueueCount(1); } @@ -246,7 +246,7 @@ public class AMQQueueFactoryTest extends QpidTestCase false, false, null); - assertEquals("Queue not a simple queue", SimpleAMQQueue.class, queue.getClass()); + assertEquals("Queue not a simple queue", StandardQueue.class, queue.getClass()); verifyQueueRegistered(queueName); //verify that no alternate exchange or DLQ were produced diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/ConflationQueueListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/ConflationQueueListTest.java index d67c70c831..c2291f5eed 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/ConflationQueueListTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/ConflationQueueListTest.java @@ -28,6 +28,9 @@ import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collections; +import java.util.UUID; + public class ConflationQueueListTest extends TestCase { private static final String CONFLATION_KEY = "CONFLATION_KEY"; @@ -37,13 +40,15 @@ public class ConflationQueueListTest extends TestCase private static final String TEST_KEY_VALUE2 = "testKeyValue2"; private ConflationQueueList _list; - private AMQQueue _queue = createTestQueue(); + private ConflationQueue _queue; @Override protected void setUp() throws Exception { super.setUp(); - _list = new ConflationQueueList(_queue, CONFLATION_KEY); + _queue = new ConflationQueue(UUID.randomUUID(), getName(), false, null, false, false, mock(VirtualHost.class), + Collections.emptyMap(),CONFLATION_KEY); + _list = _queue.getEntries(); } public void testListHasNoEntries() @@ -175,7 +180,8 @@ public class ConflationQueueListTest extends TestCase private int countEntries(ConflationQueueList list) { - QueueEntryIterator iterator = list.iterator(); + QueueEntryIterator> iterator = + list.iterator(); int count = 0; while(iterator.advance()) { diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java index 66c12717db..d1bc5effc0 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java @@ -33,6 +33,7 @@ import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.security.AuthorizationHolder; import org.apache.qpid.server.consumer.Consumer; import org.apache.qpid.server.consumer.ConsumerTarget; +import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.util.Action; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -45,7 +46,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; -public class MockAMQQueue implements AMQQueue +public class MockAMQQueue implements AMQQueue { private boolean _deleted = false; private String _name; @@ -178,6 +179,8 @@ public class MockAMQQueue implements AMQQueue return null; } + + public boolean isDurable() { return false; @@ -210,32 +213,55 @@ public class MockAMQQueue implements AMQQueue } @Override - public QueueConsumer addConsumer(final ConsumerTarget target, + public boolean resend(final QueueEntry entry, final Consumer consumer) throws AMQException + { + return false; + } + + @Override + public void addQueueDeleteTask(final Action task) + { + + } + + @Override + public void enqueue(final ServerMessage message, final Action action) throws AMQException + { + + } + + @Override + public int compareTo(final Object o) + { + return 0; + } + + @Override + public Consumer addConsumer(final ConsumerTarget target, final FilterManager filters, - final Class messageClass, + final Class messageClass, final String consumerName, - final EnumSet options) throws AMQException + final EnumSet options) throws AMQException { return new QueueConsumer(filters, messageClass, options.contains(Consumer.Option.ACQUIRES), - options.contains(Consumer.Option.SEES_REQUEUES), consumerName, - options.contains(Consumer.Option.TRANSIENT), target ); + options.contains(Consumer.Option.SEES_REQUEUES), consumerName, + options.contains(Consumer.Option.TRANSIENT), target ); } + public String getName() { return _name; } - @Override - public int send(final ServerMessage message, - final InstanceProperties instanceProperties, - final ServerTransaction txn, - final Action> postEnqueueAction) + public int send(final ServerMessage message, + final InstanceProperties instanceProperties, + final ServerTransaction txn, + final Action postEnqueueAction) { return 0; } - public Collection getConsumers() { return Collections.emptyList(); @@ -312,38 +338,39 @@ public class MockAMQQueue implements AMQQueue return getMessageCount(); } - public void enqueue(ServerMessage message, Action> action) throws AMQException - { - } - public void requeue(QueueEntry entry) { } - public void dequeue(QueueEntry entry, Consumer sub) + public void dequeue(QueueEntry entry) { } - public boolean resend(QueueEntry entry, Consumer consumer) throws AMQException + public boolean resend(QueueEntry entry, QueueConsumer consumer) throws AMQException { return false; } - public void addQueueDeleteTask(Action task) + @Override + public void removeQueueDeleteTask(final Action task) { + } - public void removeQueueDeleteTask(final Action task) + @Override + public void decrementUnackedMsgCount(final QueueEntry queueEntry) { + } - public List getMessagesOnTheQueue() + @Override + public List getMessagesOnTheQueue() { return null; } - public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) + public List getMessagesOnTheQueue(long fromMessageId, long toMessageId) { return null; } @@ -363,7 +390,7 @@ public class MockAMQQueue implements AMQQueue return null; } - public List getMessagesRangeOnTheQueue(long fromPosition, long toPosition) + public List getMessagesRangeOnTheQueue(long fromPosition, long toPosition) { return null; } @@ -570,10 +597,6 @@ public class MockAMQQueue implements AMQQueue return 0; } - public void decrementUnackedMsgCount(QueueEntry queueEntry) - { - - } public long getUnackedMessageCount() { @@ -617,4 +640,5 @@ public class MockAMQQueue implements AMQQueue { return null; } + } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java new file mode 100644 index 0000000000..386bb46044 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.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.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.filter.Filterable; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.InstanceProperties; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.util.Action; +import org.apache.qpid.server.util.StateChangeListener; + +public class MockMessageInstance implements MessageInstance +{ + + private ServerMessage _message; + + public boolean acquire() + { + return false; + } + + @Override + public int getMaximumDeliveryCount() + { + return 0; + } + + @Override + public int routeToAlternate(final Action> action, + final ServerTransaction txn) + { + return 0; + } + + public boolean acquiredByConsumer() + { + return false; + } + + @Override + public boolean isAcquiredBy(final Consumer consumer) + { + return false; + } + + public void delete() + { + + } + + public boolean expired() throws AMQException + { + return false; + } + + @Override + public boolean acquire(final Consumer sub) + { + return false; + } + + public boolean isAvailable() + { + return false; + } + + public Consumer getDeliveredConsumer() + { + return null; + } + + public boolean getDeliveredToConsumer() + { + return false; + } + + public ServerMessage getMessage() + { + return _message; + } + + public long getSize() + { + return 0; + } + + public boolean isAcquired() + { + return false; + } + + public void reject() + { + } + + @Override + public boolean isRejectedBy(final Consumer consumer) + { + return false; + } + + + public void release() + { + } + + @Override + public boolean resend() throws AMQException + { + return false; + } + + + public void setRedelivered() + { + } + + public AMQMessageHeader getMessageHeader() + { + return null; + } + + public boolean isPersistent() + { + return false; + } + + public boolean isRedelivered() + { + return false; + } + + public void setMessage(ServerMessage msg) + { + _message = msg; + } + + public boolean isDeleted() + { + return false; + } + @Override + public int getDeliveryCount() + { + return 0; + } + + @Override + public void incrementDeliveryCount() + { + } + + @Override + public void decrementDeliveryCount() + { + } + + @Override + public void addStateChangeListener(final StateChangeListener listener) + { + + } + + @Override + public boolean removeStateChangeListener(final StateChangeListener listener) + { + return false; + } + + @Override + public Filterable asFilterable() + { + return Filterable.Factory.newInstance(_message, getInstanceProperties()); + } + + @Override + public InstanceProperties getInstanceProperties() + { + return InstanceProperties.EMPTY; + } + + @Override + public TransactionLogResource getOwningResource() + { + return null; + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java deleted file mode 100644 index 89b366567d..0000000000 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.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.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.filter.Filterable; -import org.apache.qpid.server.message.AMQMessageHeader; -import org.apache.qpid.server.message.InstanceProperties; -import org.apache.qpid.server.message.MessageInstance; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.store.TransactionLogResource; -import org.apache.qpid.server.consumer.Consumer; -import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.server.util.Action; -import org.apache.qpid.server.util.StateChangeListener; - -public class MockQueueEntry implements QueueEntry -{ - - private ServerMessage _message; - - public boolean acquire() - { - return false; - } - - public boolean acquire(QueueConsumer sub) - { - return false; - } - - @Override - public int getMaximumDeliveryCount() - { - return 0; - } - - public boolean acquiredByConsumer() - { - return false; - } - - public boolean isAcquiredBy(QueueConsumer consumer) - { - return false; - } - - public void addStateChangeListener(StateChangeListener, State> listener) - { - - } - - public void delete() - { - - } - - public int routeToAlternate(final Action> action, final ServerTransaction txn) - { - return 0; - } - - public boolean expired() throws AMQException - { - return false; - } - - public boolean isAvailable() - { - return false; - } - - public QueueConsumer getDeliveredConsumer() - { - return null; - } - - public boolean getDeliveredToConsumer() - { - return false; - } - - public ServerMessage getMessage() - { - return _message; - } - - public AMQQueue getQueue() - { - return null; - } - - public long getSize() - { - return 0; - } - - public boolean isAcquired() - { - return false; - } - - - public boolean isQueueDeleted() - { - - return false; - } - - - public boolean isRejectedBy(QueueConsumer consumer) - { - - return false; - } - - - public void reject() - { - - - } - - - public void release() - { - - - } - - @Override - public boolean resend() throws AMQException - { - return false; - } - - - public boolean removeStateChangeListener(StateChangeListener, State> listener) - { - - return false; - } - - public void setRedelivered() - { - - - } - - public AMQMessageHeader getMessageHeader() - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean isPersistent() - { - return false; //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean isRedelivered() - { - return false; - } - - public int compareTo(QueueEntry o) - { - - return 0; - } - - public void setMessage(ServerMessage msg) - { - _message = msg; - } - - public boolean isDeleted() - { - return false; - } - - public QueueEntry getNextNode() - { - return null; - } - - public QueueEntry getNextValidEntry() - { - return null; - } - - @Override - public int getDeliveryCount() - { - return 0; - } - - @Override - public void incrementDeliveryCount() - { - } - - @Override - public void decrementDeliveryCount() - { - } - - @Override - public Filterable asFilterable() - { - return Filterable.Factory.newInstance(_message, getInstanceProperties()); - } - - @Override - public InstanceProperties getInstanceProperties() - { - return InstanceProperties.EMPTY; - } - - @Override - public TransactionLogResource getOwningResource() - { - return getQueue(); - } -} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueListTest.java index e8c0470915..3db5d0fb62 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueListTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueListTest.java @@ -26,12 +26,16 @@ import static org.mockito.Mockito.when; 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.virtualhost.VirtualHost; import org.apache.qpid.test.utils.QpidTestCase; +import java.util.Collections; +import java.util.UUID; + public class PriorityQueueListTest extends QpidTestCase { private static final byte[] PRIORITIES = {4, 5, 5, 4}; - PriorityQueueList _list = new PriorityQueueList(null, 10); + PriorityQueueList _list; private QueueEntry _priority4message1; private QueueEntry _priority4message2; @@ -42,6 +46,17 @@ public class PriorityQueueListTest extends QpidTestCase { QueueEntry[] entries = new QueueEntry[PRIORITIES.length]; + PriorityQueue queue = new PriorityQueue(UUID.randomUUID(), + getName(), + false, + null, + false, + false, + mock(VirtualHost.class), + Collections.emptyMap(), + 10); + _list = queue.getEntries(); + for (int i = 0; i < PRIORITIES.length; i++) { ServerMessage message = mock(ServerMessage.class); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java new file mode 100644 index 0000000000..56cd29b0bd --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.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.queue; + +import java.util.Collections; +import junit.framework.AssertionFailedError; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.ServerMessage; + +import java.util.ArrayList; +import java.util.EnumSet; + +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.consumer.Consumer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PriorityQueueTest extends SimpleAMQQueueTestBase +{ + + @Override + public void setUp() throws Exception + { + setArguments(Collections.singletonMap(Queue.PRIORITIES,(Object)3)); + super.setUp(); + } + + public void testPriorityOrdering() throws AMQException, InterruptedException + { + + // Enqueue messages in order + SimpleAMQQueue queue = getQueue(); + queue.enqueue(createMessage(1L, (byte) 10), null); + queue.enqueue(createMessage(2L, (byte) 4), null); + queue.enqueue(createMessage(3L, (byte) 0), null); + + // Enqueue messages in reverse order + queue.enqueue(createMessage(4L, (byte) 0), null); + queue.enqueue(createMessage(5L, (byte) 4), null); + queue.enqueue(createMessage(6L, (byte) 10), null); + + // Enqueue messages out of order + queue.enqueue(createMessage(7L, (byte) 4), null); + queue.enqueue(createMessage(8L, (byte) 10), null); + queue.enqueue(createMessage(9L, (byte) 0), null); + + // Register subscriber + queue.addConsumer(getConsumer(), null, null, "test", EnumSet.noneOf(Consumer.Option.class)); + Thread.sleep(150); + + ArrayList msgs = getConsumer().getMessages(); + try + { + assertEquals(1L, msgs.get(0).getMessage().getMessageNumber()); + assertEquals(6L, msgs.get(1).getMessage().getMessageNumber()); + assertEquals(8L, msgs.get(2).getMessage().getMessageNumber()); + + assertEquals(2L, msgs.get(3).getMessage().getMessageNumber()); + assertEquals(5L, msgs.get(4).getMessage().getMessageNumber()); + assertEquals(7L, msgs.get(5).getMessage().getMessageNumber()); + + assertEquals(3L, msgs.get(6).getMessage().getMessageNumber()); + assertEquals(4L, msgs.get(7).getMessage().getMessageNumber()); + assertEquals(9L, msgs.get(8).getMessage().getMessageNumber()); + } + catch (AssertionFailedError afe) + { + // Show message order on failure. + int index = 1; + for (MessageInstance qe : msgs) + { + System.err.println(index + ":" + qe.getMessage().getMessageNumber()); + index++; + } + + throw afe; + } + + } + + protected ServerMessage createMessage(Long id, byte i) throws AMQException + { + + ServerMessage msg = super.createMessage(id); + AMQMessageHeader hdr = msg.getMessageHeader(); + when(hdr.getPriority()).thenReturn(i); + return msg; + } + + protected ServerMessage createMessage(Long id) throws AMQException + { + return createMessage(id, (byte) 0); + } + +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java index 95139d8740..b67b2dda32 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java @@ -22,12 +22,18 @@ import junit.framework.TestCase; import org.apache.qpid.AMQException; import org.apache.qpid.server.consumer.ConsumerTarget; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.message.MessageInstance.EntryState; import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.lang.reflect.Field; +import java.util.Collections; +import java.util.UUID; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -57,6 +63,15 @@ public abstract class QueueEntryImplTestBase extends TestCase _queueEntry3 = getQueueEntryImpl(3); } + + protected void mockLogging() + { + final LogActor logActor = mock(LogActor.class); + when(logActor.getRootMessageLogger()).thenReturn(mock(RootMessageLogger.class)); + CurrentActor.setDefault(logActor); + } + + public void testAcquire() { assertTrue("Queue entry should be in AVAILABLE state before invoking of acquire method", @@ -185,7 +200,9 @@ public abstract class QueueEntryImplTestBase extends TestCase { int numberOfEntries = 5; QueueEntryImpl[] entries = new QueueEntryImpl[numberOfEntries]; - SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test")); + StandardQueue queue = new StandardQueue(UUID.randomUUID(), getName(), false, null, false, false, + mock(VirtualHost.class), Collections.emptyMap()); + OrderedQueueEntryList queueEntryList = queue.getEntries(); // create test entries for(int i = 0; i < numberOfEntries ; i++) diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java index a1bc9e50c7..3af268c189 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java @@ -25,6 +25,7 @@ import org.apache.qpid.AMQException; 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.consumer.Consumer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -32,20 +33,21 @@ import static org.mockito.Mockito.when; /** * Abstract test class for QueueEntryList implementations. */ -public abstract class QueueEntryListTestBase extends TestCase +public abstract class QueueEntryListTestBase, Q extends AMQQueue, L extends QueueEntryList, C extends Consumer> extends TestCase { - protected static final AMQQueue _testQueue = new MockAMQQueue("test"); - public abstract QueueEntryList getTestList(); - public abstract QueueEntryList getTestList(boolean newList); + public abstract L getTestList(); + public abstract L getTestList(boolean newList); public abstract long getExpectedFirstMsgId(); public abstract int getExpectedListLength(); public abstract ServerMessage getTestMessageToAdd() throws AMQException; public void testGetQueue() { - assertEquals("Unexpected head entry returned by getHead()", getTestList().getQueue(), _testQueue); + assertEquals("Unexpected head entry returned by getHead()", getTestList().getQueue(), getTestQueue()); } + protected abstract Q getTestQueue(); + /** * Test to add a message with properties specific to the queue type. * @see QueueEntryListTestBase#getTestList() @@ -54,10 +56,10 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testAddSpecificMessage() throws AMQException { - final QueueEntryList list = getTestList(); + final L list = getTestList(); list.add(getTestMessageToAdd()); - final QueueEntryIterator iter = list.iterator(); + final QueueEntryIterator iter = list.iterator(); int count = 0; while(iter.advance()) { @@ -75,11 +77,11 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testAddGenericMessage() throws AMQException { - final QueueEntryList list = getTestList(); + final L list = getTestList(); final ServerMessage message = createServerMessage(666l); list.add(message); - final QueueEntryIterator iter = list.iterator(); + final QueueEntryIterator iter = list.iterator(); int count = 0; while(iter.advance()) { @@ -109,8 +111,8 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testListNext() { - final QueueEntryList entryList = getTestList(); - QueueEntry entry = entryList.getHead(); + final L entryList = getTestList(); + E entry = entryList.getHead(); int count = 0; while(entryList.next(entry) != null) { @@ -127,7 +129,7 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testIterator() { - final QueueEntryIterator iter = getTestList().iterator(); + final QueueEntryIterator iter = getTestList().iterator(); int count = 0; while(iter.advance()) { @@ -145,10 +147,10 @@ public abstract class QueueEntryListTestBase extends TestCase public void testDequeuedMessagedNotPresentInIterator() throws Exception { final int numberOfMessages = getExpectedListLength(); - final QueueEntryList entryList = getTestList(); + final L entryList = getTestList(); // dequeue all even messages - final QueueEntryIterator it1 = entryList.iterator(); + final QueueEntryIterator it1 = entryList.iterator(); int counter = 0; while (it1.advance()) { @@ -161,7 +163,7 @@ public abstract class QueueEntryListTestBase extends TestCase } // iterate and check that dequeued messages are not returned by iterator - final QueueEntryIterator it2 = entryList.iterator(); + final QueueEntryIterator it2 = entryList.iterator(); int counter2 = 0; while(it2.advance()) { @@ -180,7 +182,7 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testGetHead() { - final QueueEntry head = getTestList().getHead(); + final E head = getTestList().getHead(); assertNull("Head entry should not contain an actual message", head.getMessage()); assertEquals("Unexpected message id for first list entry", getExpectedFirstMsgId(), getTestList().next(head) .getMessage().getMessageNumber()); @@ -192,16 +194,16 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testEntryDeleted() { - final QueueEntry head = getTestList().getHead(); + final E head = getTestList().getHead(); - final QueueEntry first = getTestList().next(head); + final E first = getTestList().next(head); first.delete(); - final QueueEntry second = getTestList().next(head); + final E second = getTestList().next(head); assertNotSame("After deletion the next entry should be different", first.getMessage().getMessageNumber(), second .getMessage().getMessageNumber()); - final QueueEntry third = getTestList().next(first); + final E third = getTestList().next(first); assertEquals("After deletion the deleted nodes next node should be the same as the next from head", second .getMessage().getMessageNumber(), third.getMessage().getMessageNumber()); } @@ -215,11 +217,11 @@ public abstract class QueueEntryListTestBase extends TestCase */ public void testIteratorIgnoresDeletedFinalNode() throws Exception { - QueueEntryList list = getTestList(true); + L list = getTestList(true); int i = 0; - QueueEntry queueEntry1 = list.add(createServerMessage(i++)); - QueueEntry queueEntry2 = list.add(createServerMessage(i++)); + E queueEntry1 = list.add(createServerMessage(i++)); + E queueEntry2 = list.add(createServerMessage(i++)); assertSame(queueEntry2, list.next(queueEntry1)); assertNull(list.next(queueEntry2)); @@ -228,7 +230,7 @@ public abstract class QueueEntryListTestBase extends TestCase queueEntry2.delete(); assertTrue("Deleting node should have succeeded", queueEntry2.isDeleted()); - QueueEntryIterator iter = list.iterator(); + QueueEntryIterator iter = list.iterator(); //verify the iterator isn't 'atTail', can advance, and returns the 1st QueueEntry assertFalse("Iterator should not have been 'atTail'", iter.atTail()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java index 674af36b77..87182dc8dc 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SelfValidatingSortedQueueEntryList.java @@ -22,7 +22,7 @@ package org.apache.qpid.server.queue; import junit.framework.Assert; import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour; +import org.apache.qpid.server.queue.SortedQueueEntry.Colour; /** * Test extension of SortedQueueEntryList that provides data structure validation tests. @@ -30,22 +30,28 @@ import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour; */ public class SelfValidatingSortedQueueEntryList extends SortedQueueEntryList { - public SelfValidatingSortedQueueEntryList(AMQQueue queue, String propertyName) + public SelfValidatingSortedQueueEntryList(SortedQueue queue, String propertyName) { super(queue, propertyName); } + @Override + public SortedQueue getQueue() + { + return super.getQueue(); + } + @Override /** Overridden to automatically check queue properties before and after. */ - public SortedQueueEntryImpl add(final ServerMessage message) + public SortedQueueEntry add(final ServerMessage message) { assertQueueProperties(); //before add - final SortedQueueEntryImpl result = super.add(message); + final SortedQueueEntry result = super.add(message); assertQueueProperties(); //after add return result; } @Override /** Overridden to automatically check queue properties before and after. */ - public void entryDeleted(SortedQueueEntryImpl entry) + public void entryDeleted(SortedQueueEntry entry) { assertQueueProperties(); //before delete super.entryDeleted(entry); @@ -73,7 +79,7 @@ public class SelfValidatingSortedQueueEntryList extends SortedQueueEntryList assertTreeIntegrity(getRoot()); } - public void assertTreeIntegrity(final SortedQueueEntryImpl node) + public void assertTreeIntegrity(final SortedQueueEntry node) { if(node == null) { @@ -109,7 +115,7 @@ public class SelfValidatingSortedQueueEntryList extends SortedQueueEntryList assertLeavesSameBlackPath(getRoot()); } - public int assertLeavesSameBlackPath(final SortedQueueEntryImpl node) + public int assertLeavesSameBlackPath(final SortedQueueEntry node) { if(node == null) { @@ -133,7 +139,7 @@ public class SelfValidatingSortedQueueEntryList extends SortedQueueEntryList assertChildrenOfRedAreBlack(getRoot()); } - public void assertChildrenOfRedAreBlack(final SortedQueueEntryImpl node) + public void assertChildrenOfRedAreBlack(final SortedQueueEntry node) { if(node == null) { diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java deleted file mode 100644 index 5abc97cee9..0000000000 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java +++ /dev/null @@ -1,1343 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.queue; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Matchers.contains; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Map; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.AMQSecurityException; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.server.exchange.DirectExchange; -import org.apache.qpid.server.message.AMQMessageHeader; -import org.apache.qpid.server.message.MessageInstance; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.model.UUIDGenerator; -import org.apache.qpid.server.queue.SimpleAMQQueue.QueueEntryFilter; -import org.apache.qpid.server.consumer.ConsumerTarget; -import org.apache.qpid.server.consumer.MockConsumer; -import org.apache.qpid.server.consumer.Consumer; -import org.apache.qpid.server.util.Action; -import org.apache.qpid.server.util.BrokerTestHelper; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.test.utils.QpidTestCase; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class SimpleAMQQueueTest extends QpidTestCase -{ - private static final Logger _logger = Logger.getLogger(SimpleAMQQueueTest.class); - - private SimpleAMQQueue _queue; - private VirtualHost _virtualHost; - private String _qname = "qname"; - private String _owner = "owner"; - private String _routingKey = "routing key"; - private DirectExchange _exchange; - private MockConsumer _consumerTarget = new MockConsumer(); - private QueueConsumer _consumer; - private Map _arguments = null; - - @Override - public void setUp() throws Exception - { - super.setUp(); - BrokerTestHelper.setUp(); - - _virtualHost = BrokerTestHelper.createVirtualHost(getClass().getName()); - - _queue = (SimpleAMQQueue) _virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), _qname, false, _owner, - false, false, false, _arguments); - - _exchange = (DirectExchange) _virtualHost.getExchange(ExchangeDefaults.DIRECT_EXCHANGE_NAME); - } - - @Override - public void tearDown() throws Exception - { - try - { - _queue.stop(); - _virtualHost.close(); - } - finally - { - BrokerTestHelper.tearDown(); - super.tearDown(); - } - } - - public void testCreateQueue() throws AMQException - { - _queue.stop(); - try - { - _queue = (SimpleAMQQueue) _virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), null, - false, _owner, false, - false, false, _arguments); - assertNull("Queue was created", _queue); - } - catch (IllegalArgumentException e) - { - assertTrue("Exception was not about missing name", - e.getMessage().contains("name")); - } - - try - { - _queue = new SimpleAMQQueue(UUIDGenerator.generateRandomUUID(), _qname, false, _owner, false,false, null, Collections.EMPTY_MAP); - assertNull("Queue was created", _queue); - } - catch (IllegalArgumentException e) - { - assertTrue("Exception was not about missing vhost", - e.getMessage().contains("Host")); - } - - _queue = (SimpleAMQQueue) _virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), - "differentName", false, - _owner, false, - false, false, _arguments); - assertNotNull("Queue was not created", _queue); - } - - public void testGetVirtualHost() - { - assertEquals("Virtual host was wrong", _virtualHost, _queue.getVirtualHost()); - } - - public void testBinding() throws AMQSecurityException, AMQInternalException - { - _exchange.addBinding(_routingKey, _queue, Collections.EMPTY_MAP); - - assertTrue("Routing key was not bound", - _exchange.isBound(_routingKey)); - assertTrue("Queue was not bound to key", - _exchange.isBound(_routingKey,_queue)); - assertEquals("Exchange binding count", 1, - _queue.getBindings().size()); - assertEquals("Wrong exchange bound", _routingKey, - _queue.getBindings().get(0).getBindingKey()); - assertEquals("Wrong exchange bound", _exchange, - _queue.getBindings().get(0).getExchange()); - - _exchange.removeBinding(_routingKey, _queue, Collections.EMPTY_MAP); - assertFalse("Routing key was still bound", - _exchange.isBound(_routingKey)); - - } - - public void testRegisterConsumerThenEnqueueMessage() throws AMQException - { - ServerMessage messageA = createMessage(new Long(24)); - - // Check adding a consumer adds it to the queue - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - assertEquals("Queue does not have consumer", 1, - _queue.getConsumerCount()); - assertEquals("Queue does not have active consumer", 1, - _queue.getActiveConsumerCount()); - - // Check sending a message ends up with the subscriber - _queue.enqueue(messageA, null); - try - { - Thread.sleep(2000L); - } - catch(InterruptedException e) - { - } - assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage()); - assertNull(_consumer.getQueueContext().getReleasedEntry()); - - // Check removing the consumer removes it's information from the queue - _consumer.close(); - assertTrue("Consumer still had queue", _consumerTarget.isClosed()); - assertFalse("Queue still has consumer", 1 == _queue.getConsumerCount()); - assertFalse("Queue still has active consumer", - 1 == _queue.getActiveConsumerCount()); - - ServerMessage messageB = createMessage(new Long (25)); - _queue.enqueue(messageB, null); - assertNull(_consumer.getQueueContext()); - - } - - public void testEnqueueMessageThenRegisterConsumer() throws AMQException, InterruptedException - { - ServerMessage messageA = createMessage(new Long(24)); - _queue.enqueue(messageA, null); - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - Thread.sleep(150); - assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage()); - assertNull("There should be no releasedEntry after an enqueue", - _consumer.getQueueContext().getReleasedEntry()); - } - - /** - * Tests enqueuing two messages. - */ - public void testEnqueueTwoMessagesThenRegisterConsumer() throws Exception - { - ServerMessage messageA = createMessage(new Long(24)); - ServerMessage messageB = createMessage(new Long(25)); - _queue.enqueue(messageA, null); - _queue.enqueue(messageB, null); - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - Thread.sleep(150); - assertEquals(messageB, _consumer.getQueueContext().getLastSeenEntry().getMessage()); - assertNull("There should be no releasedEntry after enqueues", - _consumer.getQueueContext().getReleasedEntry()); - } - - /** - * Tests that a released queue entry is resent to the subscriber. Verifies also that the - * QueueContext._releasedEntry is reset to null after the entry has been reset. - */ - public void testReleasedMessageIsResentToSubscriber() throws Exception - { - - ServerMessage messageA = createMessage(new Long(24)); - ServerMessage messageB = createMessage(new Long(25)); - ServerMessage messageC = createMessage(new Long(26)); - - - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - final ArrayList queueEntries = new ArrayList(); - EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); - - /* Enqueue three messages */ - - _queue.enqueue(messageA, postEnqueueAction); - _queue.enqueue(messageB, postEnqueueAction); - _queue.enqueue(messageC, postEnqueueAction); - - Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to consumer", - 3, - _consumerTarget.getMessages().size()); - assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); - assertFalse("Redelivery flag should not be set", queueEntries.get(1).isRedelivered()); - assertFalse("Redelivery flag should not be set", queueEntries.get(2).isRedelivered()); - - /* Now release the first message only, causing it to be requeued */ - - queueEntries.get(0).release(); - - Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to consumer", - 4, - _consumerTarget.getMessages().size()); - assertTrue("Redelivery flag should now be set", queueEntries.get(0).isRedelivered()); - assertFalse("Redelivery flag should remain be unset", queueEntries.get(1).isRedelivered()); - assertFalse("Redelivery flag should remain be unset",queueEntries.get(2).isRedelivered()); - assertNull("releasedEntry should be cleared after requeue processed", - _consumer.getQueueContext().getReleasedEntry()); - } - - /** - * Tests that a released message that becomes expired is not resent to the subscriber. - * This tests ensures that SimpleAMQQueueEntry.getNextAvailableEntry avoids expired entries. - * Verifies also that the QueueContext._releasedEntry is reset to null after the entry has been reset. - */ - public void testReleaseMessageThatBecomesExpiredIsNotRedelivered() throws Exception - { - ServerMessage messageA = createMessage(new Long(24)); - - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.SEES_REQUEUES, - Consumer.Option.ACQUIRES)); - - final ArrayList queueEntries = new ArrayList(); - EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); - - /* Enqueue one message with expiration set for a short time in the future */ - - int messageExpirationOffset = 200; - final long expiration = System.currentTimeMillis() + messageExpirationOffset; - when(messageA.getExpiration()).thenReturn(expiration); - - _queue.enqueue(messageA, postEnqueueAction); - - int subFlushWaitTime = 150; - Thread.sleep(subFlushWaitTime); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to consumer", - 1, - _consumerTarget.getMessages().size()); - assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); - - /* Wait a little more to be sure that message will have expired, then release the first message only, causing it to be requeued */ - Thread.sleep(messageExpirationOffset - subFlushWaitTime + 10); - queueEntries.get(0).release(); - - Thread.sleep(subFlushWaitTime); // Work done by SubFlushRunner/QueueRunner Threads - - assertTrue("Expecting the queue entry to be now expired", queueEntries.get(0).expired()); - assertEquals("Total number of messages sent should not have changed", - 1, - _consumerTarget.getMessages().size()); - assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); - assertNull("releasedEntry should be cleared after requeue processed", - _consumer.getQueueContext().getReleasedEntry()); - - } - - /** - * Tests that if a client releases entries 'out of order' (the order - * used by QueueEntryImpl.compareTo) that messages are still resent - * successfully. Specifically this test ensures the {@see SimpleAMQQueue#requeue()} - * can correctly move the _releasedEntry to an earlier position in the QueueEntry list. - */ - public void testReleasedOutOfComparableOrderAreRedelivered() throws Exception - { - - ServerMessage messageA = createMessage(new Long(24)); - ServerMessage messageB = createMessage(new Long(25)); - ServerMessage messageC = createMessage(new Long(26)); - - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - final ArrayList queueEntries = new ArrayList(); - EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); - - /* Enqueue three messages */ - - _queue.enqueue(messageA, postEnqueueAction); - _queue.enqueue(messageB, postEnqueueAction); - _queue.enqueue(messageC, postEnqueueAction); - - Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to consumer", - 3, - _consumerTarget.getMessages().size()); - assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); - assertFalse("Redelivery flag should not be set", queueEntries.get(1).isRedelivered()); - assertFalse("Redelivery flag should not be set", queueEntries.get(2).isRedelivered()); - - /* Now release the third and first message only, causing it to be requeued */ - - queueEntries.get(2).release(); - queueEntries.get(0).release(); - - Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to consumer", - 5, - _consumerTarget.getMessages().size()); - assertTrue("Redelivery flag should now be set", queueEntries.get(0).isRedelivered()); - assertFalse("Redelivery flag should remain be unset", queueEntries.get(1).isRedelivered()); - assertTrue("Redelivery flag should now be set",queueEntries.get(2).isRedelivered()); - assertNull("releasedEntry should be cleared after requeue processed", - _consumer.getQueueContext().getReleasedEntry()); - } - - - /** - * Tests that a release requeues an entry for a queue with multiple consumers. Verifies that a - * requeue resends a message to a single subscriber. - */ - public void testReleaseForQueueWithMultipleConsumers() throws Exception - { - ServerMessage messageA = createMessage(new Long(24)); - ServerMessage messageB = createMessage(new Long(25)); - - MockConsumer target1 = new MockConsumer(); - MockConsumer target2 = new MockConsumer(); - - - QueueConsumer consumer1 = _queue.addConsumer(target1, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - QueueConsumer consumer2 = _queue.addConsumer(target2, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - - final ArrayList queueEntries = new ArrayList(); - EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); - - /* Enqueue two messages */ - - _queue.enqueue(messageA, postEnqueueAction); - _queue.enqueue(messageB, postEnqueueAction); - - Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to both after enqueue", - 2, - target1.getMessages().size() + target2.getMessages().size()); - - /* Now release the first message only, causing it to be requeued */ - queueEntries.get(0).release(); - - Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads - - assertEquals("Unexpected total number of messages sent to both consumers after release", - 3, - target1.getMessages().size() + target2.getMessages().size()); - assertNull("releasedEntry should be cleared after requeue processed", - consumer1.getQueueContext().getReleasedEntry()); - assertNull("releasedEntry should be cleared after requeue processed", - consumer2.getQueueContext().getReleasedEntry()); - } - - public void testExclusiveConsumer() throws AMQException - { - ServerMessage messageA = createMessage(new Long(24)); - // Check adding an exclusive consumer adds it to the queue - - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.EXCLUSIVE, Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - assertEquals("Queue does not have consumer", 1, - _queue.getConsumerCount()); - assertEquals("Queue does not have active consumer", 1, - _queue.getActiveConsumerCount()); - - // Check sending a message ends up with the subscriber - _queue.enqueue(messageA, null); - try - { - Thread.sleep(2000L); - } - catch (InterruptedException e) - { - } - assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage()); - - // Check we cannot add a second subscriber to the queue - MockConsumer subB = new MockConsumer(); - Exception ex = null; - try - { - - _queue.addConsumer(subB, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - } - catch (AMQException e) - { - ex = e; - } - assertNotNull(ex); - - // Check we cannot add an exclusive subscriber to a queue with an - // existing consumer - _consumer.close(); - _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - try - { - - _consumer = _queue.addConsumer(subB, null, messageA.getClass(), "test", - EnumSet.of(Consumer.Option.EXCLUSIVE)); - - } - catch (AMQException e) - { - ex = e; - } - assertNotNull(ex); - } - - public void testAutoDeleteQueue() throws Exception - { - _queue.stop(); - _queue = new SimpleAMQQueue(UUIDGenerator.generateRandomUUID(), _qname, false, null, true, false, _virtualHost, Collections.EMPTY_MAP); - _queue.setDeleteOnNoConsumers(true); - - ServerMessage message = createMessage(new Long(25)); - _consumer = _queue.addConsumer(_consumerTarget, null, message.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - _queue.enqueue(message, null); - _consumer.close(); - assertTrue("Queue was not deleted when consumer was removed", - _queue.isDeleted()); - } - - public void testResend() throws Exception - { - Long id = new Long(26); - ServerMessage message = createMessage(id); - - _consumer = _queue.addConsumer(_consumerTarget, null, message.getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); - - _queue.enqueue(message, new Action>() - { - @Override - public void performAction(final MessageInstance object) - { - QueueEntry entry = (QueueEntry) object; - entry.setRedelivered(); - try - { - _consumer.resend(entry); - } - catch (AMQException e) - { - fail("Exception thrown: " + e.getMessage()); - } - } - }); - - - - } - - public void testGetFirstMessageId() throws Exception - { - // Create message - Long messageId = new Long(23); - ServerMessage message = createMessage(messageId); - - // Put message on queue - _queue.enqueue(message, null); - // Get message id - Long testmsgid = _queue.getMessagesOnTheQueue(1).get(0); - - // Check message id - assertEquals("Message ID was wrong", messageId, testmsgid); - } - - public void testGetFirstFiveMessageIds() throws Exception - { - for (int i = 0 ; i < 5; i++) - { - // Create message - Long messageId = new Long(i); - ServerMessage message = createMessage(messageId); - // Put message on queue - _queue.enqueue(message, null); - } - // Get message ids - List msgids = _queue.getMessagesOnTheQueue(5); - - // Check message id - for (int i = 0; i < 5; i++) - { - Long messageId = new Long(i); - assertEquals("Message ID was wrong", messageId, msgids.get(i)); - } - } - - public void testGetLastFiveMessageIds() throws Exception - { - for (int i = 0 ; i < 10; i++) - { - // Create message - Long messageId = new Long(i); - ServerMessage message = createMessage(messageId); - // Put message on queue - _queue.enqueue(message, null); - } - // Get message ids - List msgids = _queue.getMessagesOnTheQueue(5, 5); - - // Check message id - for (int i = 0; i < 5; i++) - { - Long messageId = new Long(i+5); - assertEquals("Message ID was wrong", messageId, msgids.get(i)); - } - } - - public void testGetMessagesRangeOnTheQueue() throws Exception - { - for (int i = 1 ; i <= 10; i++) - { - // Create message - Long messageId = new Long(i); - ServerMessage message = createMessage(messageId); - // Put message on queue - _queue.enqueue(message, null); - } - - // Get non-existent 0th QueueEntry & check returned list was empty - // (the position parameters in this method are indexed from 1) - List entries = _queue.getMessagesRangeOnTheQueue(0, 0); - assertTrue(entries.size() == 0); - - // Check that when 'from' is 0 it is ignored and the range continues from 1 - entries = _queue.getMessagesRangeOnTheQueue(0, 2); - assertTrue(entries.size() == 2); - long msgID = entries.get(0).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 1L); - msgID = entries.get(1).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 2L); - - // Check that when 'from' is greater than 'to' the returned list is empty - entries = _queue.getMessagesRangeOnTheQueue(5, 4); - assertTrue(entries.size() == 0); - - // Get first QueueEntry & check id - entries = _queue.getMessagesRangeOnTheQueue(1, 1); - assertTrue(entries.size() == 1); - msgID = entries.get(0).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 1L); - - // Get 5th,6th,7th entries and check id's - entries = _queue.getMessagesRangeOnTheQueue(5, 7); - assertTrue(entries.size() == 3); - msgID = entries.get(0).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 5L); - msgID = entries.get(1).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 6L); - msgID = entries.get(2).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 7L); - - // Get 10th QueueEntry & check id - entries = _queue.getMessagesRangeOnTheQueue(10, 10); - assertTrue(entries.size() == 1); - msgID = entries.get(0).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 10L); - - // Get non-existent 11th QueueEntry & check returned set was empty - entries = _queue.getMessagesRangeOnTheQueue(11, 11); - assertTrue(entries.size() == 0); - - // Get 9th,10th, and non-existent 11th entries & check result is of size 2 with correct IDs - entries = _queue.getMessagesRangeOnTheQueue(9, 11); - assertTrue(entries.size() == 2); - msgID = entries.get(0).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 9L); - msgID = entries.get(1).getMessage().getMessageNumber(); - assertEquals("Message ID was wrong", msgID, 10L); - } - - - /** - * processQueue() is used when asynchronously delivering messages to - * consumers which could not be delivered immediately during the - * enqueue() operation. - * - * A defect within the method would mean that delivery of these messages may - * not occur should the Runner stop before all messages have been processed. - * Such a defect was discovered when Selectors were used such that one and - * only one consumer can/will accept any given messages, but multiple - * consumers are present, and one of the earlier consumers receives - * more messages than the others. - * - * This test is to validate that the processQueue() method is able to - * correctly deliver all of the messages present for asynchronous delivery - * to consumers in such a scenario. - */ - public void testProcessQueueWithUniqueSelectors() throws Exception - { - TestSimpleQueueEntryListFactory factory = new TestSimpleQueueEntryListFactory(); - SimpleAMQQueue testQueue = new SimpleAMQQueue(UUIDGenerator.generateRandomUUID(), "testQueue", false,"testOwner", - false, false, _virtualHost, factory, null) - { - @Override - public void deliverAsync(QueueConsumer sub) - { - // do nothing, i.e prevent deliveries by the SubFlushRunner - // when registering the new consumers - } - }; - - // retrieve the QueueEntryList the queue creates and insert the test - // messages, thus avoiding straight-through delivery attempts during - //enqueue() process. - QueueEntryList list = factory.getQueueEntryList(); - assertNotNull("QueueEntryList should have been created", list); - - QueueEntry msg1 = list.add(createMessage(1L)); - QueueEntry msg2 = list.add(createMessage(2L)); - QueueEntry msg3 = list.add(createMessage(3L)); - QueueEntry msg4 = list.add(createMessage(4L)); - QueueEntry msg5 = list.add(createMessage(5L)); - - // Create lists of the entries each consumer should be interested - // in.Bias over 50% of the messages to the first consumer so that - // the later consumers reject them and report being done before - // the first consumer as the processQueue method proceeds. - List msgListSub1 = createEntriesList(msg1, msg2, msg3); - List msgListSub2 = createEntriesList(msg4); - List msgListSub3 = createEntriesList(msg5); - - MockConsumer sub1 = new MockConsumer(msgListSub1); - MockConsumer sub2 = new MockConsumer(msgListSub2); - MockConsumer sub3 = new MockConsumer(msgListSub3); - - // register the consumers - testQueue.addConsumer(sub1, sub1.getFilters(), msg1.getMessage().getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); - testQueue.addConsumer(sub2, sub2.getFilters(), msg1.getMessage().getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); - testQueue.addConsumer(sub3, sub3.getFilters(), msg1.getMessage().getClass(), "test", - EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); - - //check that no messages have been delivered to the - //consumers during registration - assertEquals("No messages should have been delivered yet", 0, sub1.getMessages().size()); - assertEquals("No messages should have been delivered yet", 0, sub2.getMessages().size()); - assertEquals("No messages should have been delivered yet", 0, sub3.getMessages().size()); - - // call processQueue to deliver the messages - testQueue.processQueue(new QueueRunner(testQueue) - { - @Override - public void run() - { - // we don't actually want/need this runner to do any work - // because we we are already doing it! - } - }); - - // check expected messages delivered to correct consumers - verifyReceivedMessages(Arrays.asList((MessageInstance)msg1,msg2,msg3), sub1.getMessages()); - verifyReceivedMessages(Collections.singletonList((MessageInstance)msg4), sub2.getMessages()); - verifyReceivedMessages(Collections.singletonList((MessageInstance)msg5), sub3.getMessages()); - } - - /** - * Tests that dequeued message is not present in the list returned form - * {@link SimpleAMQQueue#getMessagesOnTheQueue()} - */ - public void testGetMessagesOnTheQueueWithDequeuedEntry() - { - int messageNumber = 4; - int dequeueMessageIndex = 1; - - // send test messages into a test queue - enqueueGivenNumberOfMessages(_queue, messageNumber); - - // dequeue message - dequeueMessage(_queue, dequeueMessageIndex); - - // get messages on the queue - List entries = _queue.getMessagesOnTheQueue(); - - // assert queue entries - assertEquals(messageNumber - 1, entries.size()); - int expectedId = 0; - for (int i = 0; i < messageNumber - 1; i++) - { - Long id = ( entries.get(i).getMessage()).getMessageNumber(); - if (i == dequeueMessageIndex) - { - assertFalse("Message with id " + dequeueMessageIndex - + " was dequeued and should not be returned by method getMessagesOnTheQueue!", - new Long(expectedId).equals(id)); - expectedId++; - } - assertEquals("Expected message with id " + expectedId + " but got message with id " + id, - new Long(expectedId), id); - expectedId++; - } - } - - /** - * Tests that dequeued message is not present in the list returned form - * {@link SimpleAMQQueue#getMessagesOnTheQueue(QueueEntryFilter)} - */ - public void testGetMessagesOnTheQueueByQueueEntryFilterWithDequeuedEntry() - { - int messageNumber = 4; - int dequeueMessageIndex = 1; - - // send test messages into a test queue - enqueueGivenNumberOfMessages(_queue, messageNumber); - - // dequeue message - dequeueMessage(_queue, dequeueMessageIndex); - - // get messages on the queue with filter accepting all available messages - List entries = _queue.getMessagesOnTheQueue(new QueueEntryFilter() - { - public boolean accept(QueueEntry entry) - { - return true; - } - - public boolean filterComplete() - { - return false; - } - }); - - // assert entries on the queue - assertEquals(messageNumber - 1, entries.size()); - int expectedId = 0; - for (int i = 0; i < messageNumber - 1; i++) - { - Long id = (entries.get(i).getMessage()).getMessageNumber(); - if (i == dequeueMessageIndex) - { - assertFalse("Message with id " + dequeueMessageIndex - + " was dequeued and should not be returned by method getMessagesOnTheQueue!", - new Long(expectedId).equals(id)); - expectedId++; - } - assertEquals("Expected message with id " + expectedId + " but got message with id " + id, - new Long(expectedId), id); - expectedId++; - } - } - - - - /** - * Tests that dequeued message on the top is not accounted and next message - * is deleted from the queue on invocation of - * {@link SimpleAMQQueue#deleteMessageFromTop()} - */ - public void testDeleteMessageFromTopWithDequeuedEntryOnTop() - { - int messageNumber = 4; - int dequeueMessageIndex = 0; - - // put messages into a test queue - enqueueGivenNumberOfMessages(_queue, messageNumber); - - // dequeue message on top - dequeueMessage(_queue, dequeueMessageIndex); - - //delete message from top - _queue.deleteMessageFromTop(); - - //get queue entries - List entries = _queue.getMessagesOnTheQueue(); - - // assert queue entries - assertNotNull("Null is returned from getMessagesOnTheQueue", entries); - assertEquals("Expected " + (messageNumber - 2) + " number of messages but recieved " + entries.size(), - messageNumber - 2, entries.size()); - assertEquals("Expected first entry with id 2", 2l, - (entries.get(0).getMessage()).getMessageNumber()); - } - - /** - * Tests that all messages including dequeued one are deleted from the queue - * on invocation of {@link SimpleAMQQueue#clearQueue()} - */ - public void testClearQueueWithDequeuedEntry() - { - int messageNumber = 4; - int dequeueMessageIndex = 1; - - // put messages into a test queue - enqueueGivenNumberOfMessages(_queue, messageNumber); - - // dequeue message on a test queue - dequeueMessage(_queue, dequeueMessageIndex); - - // clean queue - try - { - _queue.clearQueue(); - } - catch (AMQException e) - { - fail("Failure to clear queue:" + e.getMessage()); - } - - // get queue entries - List entries = _queue.getMessagesOnTheQueue(); - - // assert queue entries - assertNotNull(entries); - assertEquals(0, entries.size()); - } - - /** - * Tests whether dequeued entry is sent to subscriber in result of - * invocation of {@link SimpleAMQQueue#processQueue(QueueRunner)} - */ - public void testProcessQueueWithDequeuedEntry() - { - // total number of messages to send - int messageNumber = 4; - int dequeueMessageIndex = 1; - - // create queue with overridden method deliverAsync - SimpleAMQQueue testQueue = new SimpleAMQQueue(UUIDGenerator.generateRandomUUID(), "test", - false, "testOwner", false, false, _virtualHost, null) - { - @Override - public void deliverAsync(QueueConsumer sub) - { - // do nothing - } - }; - - // put messages - List entries = enqueueGivenNumberOfMessages(testQueue, messageNumber); - - // dequeue message - dequeueMessage(testQueue, dequeueMessageIndex); - - // latch to wait for message receipt - final CountDownLatch latch = new CountDownLatch(messageNumber -1); - - // create a consumer - MockConsumer consumer = new MockConsumer() - { - /** - * Send a message and decrement latch - * @param entry - * @param batch - */ - public void send(MessageInstance entry, boolean batch) throws AMQException - { - super.send(entry, batch); - latch.countDown(); - } - }; - - try - { - // subscribe - testQueue.addConsumer(consumer, - null, - entries.get(0).getMessage().getClass(), - "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - - // process queue - testQueue.processQueue(new QueueRunner(testQueue) - { - public void run() - { - // do nothing - } - }); - } - catch (AMQException e) - { - fail("Failure to process queue:" + e.getMessage()); - } - // wait up to 1 minute for message receipt - try - { - latch.await(1, TimeUnit.MINUTES); - } - catch (InterruptedException e1) - { - Thread.currentThread().interrupt(); - } - List expected = Arrays.asList((MessageInstance)entries.get(0), entries.get(2), entries.get(3)); - verifyReceivedMessages(expected, consumer.getMessages()); - } - - /** - * Tests that entry in dequeued state are not enqueued and not delivered to consumer - */ - public void testEnqueueDequeuedEntry() - { - // create a queue where each even entry is considered a dequeued - SimpleAMQQueue queue = new SimpleAMQQueue(UUIDGenerator.generateRandomUUID(), "test", false, - "testOwner", false, false, _virtualHost, new QueueEntryListFactory() - { - public QueueEntryList createQueueEntryList(AMQQueue queue) - { - /** - * Override SimpleQueueEntryList to create a dequeued - * entries for messages with even id - */ - return new SimpleQueueEntryList(queue) - { - /** - * Entries with even message id are considered - * dequeued! - */ - protected SimpleQueueEntryImpl createQueueEntry(final ServerMessage message) - { - return new SimpleQueueEntryImpl(this, message) - { - - public boolean isDeleted() - { - return (message.getMessageNumber() % 2 == 0); - } - - public boolean isAvailable() - { - return !(message.getMessageNumber() % 2 == 0); - } - - @Override - public boolean acquire(QueueConsumer sub) - { - if(message.getMessageNumber() % 2 == 0) - { - return false; - } - else - { - return super.acquire(sub); - } - } - }; - } - }; - } - }, null); - // create a consumer - MockConsumer consumer = new MockConsumer(); - - // register consumer - try - { - queue.addConsumer(consumer, - null, - createMessage(-1l).getClass(), - "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - } - catch (AMQException e) - { - fail("Failure to register consumer:" + e.getMessage()); - } - - // put test messages into a queue - putGivenNumberOfMessages(queue, 4); - - // assert received messages - List messages = consumer.getMessages(); - assertEquals("Only 2 messages should be returned", 2, messages.size()); - assertEquals("ID of first message should be 1", 1l, - (messages.get(0).getMessage()).getMessageNumber()); - assertEquals("ID of second message should be 3", 3l, - (messages.get(1).getMessage()).getMessageNumber()); - } - - public void testActiveConsumerCount() throws Exception - { - final SimpleAMQQueue queue = new SimpleAMQQueue(UUIDGenerator.generateRandomUUID(), "testActiveConsumerCount", false, - "testOwner", false, false, _virtualHost, new SimpleQueueEntryList.Factory(), null); - - //verify adding an active consumer increases the count - final MockConsumer consumer1 = new MockConsumer(); - consumer1.setActive(true); - consumer1.setState(ConsumerTarget.State.ACTIVE); - assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); - queue.addConsumer(consumer1, - null, - createMessage(-1l).getClass(), - "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - - //verify adding an inactive consumer doesn't increase the count - final MockConsumer consumer2 = new MockConsumer(); - consumer2.setActive(false); - consumer2.setState(ConsumerTarget.State.SUSPENDED); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - queue.addConsumer(consumer2, - null, - createMessage(-1l).getClass(), - "test", - EnumSet.of(Consumer.Option.ACQUIRES, - Consumer.Option.SEES_REQUEUES)); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - - //verify behaviour in face of expected state changes: - - //verify a consumer going suspended->active increases the count - consumer2.setState(ConsumerTarget.State.ACTIVE); - assertEquals("Unexpected active consumer count", 2, queue.getActiveConsumerCount()); - - //verify a consumer going active->suspended decreases the count - consumer2.setState(ConsumerTarget.State.SUSPENDED); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - - //verify a consumer going suspended->closed doesn't change the count - consumer2.setState(ConsumerTarget.State.CLOSED); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - - //verify a consumer going active->active doesn't change the count - consumer1.setState(ConsumerTarget.State.ACTIVE); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - - consumer1.setState(ConsumerTarget.State.SUSPENDED); - assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); - - //verify a consumer going suspended->suspended doesn't change the count - consumer1.setState(ConsumerTarget.State.SUSPENDED); - assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); - - consumer1.setState(ConsumerTarget.State.ACTIVE); - assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); - - //verify a consumer going active->closed decreases the count - consumer1.setState(ConsumerTarget.State.CLOSED); - assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); - - } - - public void testNotificationFiredOnEnqueue() throws Exception - { - AMQQueue.NotificationListener listener = mock(AMQQueue.NotificationListener.class); - - _queue.setNotificationListener(listener); - _queue.setMaximumMessageCount(2); - - _queue.enqueue(createMessage(new Long(24)), null); - verifyZeroInteractions(listener); - - _queue.enqueue(createMessage(new Long(25)), null); - - verify(listener, atLeastOnce()).notifyClients(eq(NotificationCheck.MESSAGE_COUNT_ALERT), eq(_queue), contains("Maximum count on queue threshold")); - } - - public void testNotificationFiredAsync() throws Exception - { - AMQQueue.NotificationListener listener = mock(AMQQueue.NotificationListener.class); - - _queue.enqueue(createMessage(new Long(24)), null); - _queue.enqueue(createMessage(new Long(25)), null); - _queue.enqueue(createMessage(new Long(26)), null); - - _queue.setNotificationListener(listener); - _queue.setMaximumMessageCount(2); - - verifyZeroInteractions(listener); - - _queue.checkMessageStatus(); - - verify(listener, atLeastOnce()).notifyClients(eq(NotificationCheck.MESSAGE_COUNT_ALERT), eq(_queue), contains("Maximum count on queue threshold")); - } - - /** - * A helper method to put given number of messages into queue - *

- * All messages are asserted that they are present on queue - * - * @param queue - * queue to put messages into - * @param messageNumber - * number of messages to put into queue - */ - private List enqueueGivenNumberOfMessages(AMQQueue queue, int messageNumber) - { - putGivenNumberOfMessages(queue, messageNumber); - - // make sure that all enqueued messages are on the queue - List entries = queue.getMessagesOnTheQueue(); - assertEquals(messageNumber, entries.size()); - for (int i = 0; i < messageNumber; i++) - { - assertEquals((long)i, (entries.get(i).getMessage()).getMessageNumber()); - } - return entries; - } - - /** - * A helper method to put given number of messages into queue - *

- * Queue is not checked if messages are added into queue - * - * @param queue - * queue to put messages into - * @param messageNumber - * number of messages to put into queue - * @param queue - * @param messageNumber - */ - private void putGivenNumberOfMessages(AMQQueue queue, int messageNumber) - { - for (int i = 0; i < messageNumber; i++) - { - // Create message - Long messageId = new Long(i); - ServerMessage message = null; - try - { - message = createMessage(messageId); - } - catch (AMQException e) - { - fail("Failure to create a test message:" + e.getMessage()); - } - // Put message on queue - try - { - queue.enqueue(message,null); - } - catch (AMQException e) - { - fail("Failure to put message on queue:" + e.getMessage()); - } - } - try - { - Thread.sleep(2000L); - } - catch (InterruptedException e) - { - _logger.error("Thread interrupted", e); - } - } - - /** - * A helper method to dequeue an entry on queue with given index - * - * @param queue - * queue to dequeue message on - * @param dequeueMessageIndex - * entry index to dequeue. - */ - private QueueEntry dequeueMessage(AMQQueue queue, int dequeueMessageIndex) - { - List entries = queue.getMessagesOnTheQueue(); - QueueEntry entry = entries.get(dequeueMessageIndex); - entry.acquire(); - entry.delete(); - assertTrue(entry.isDeleted()); - return entry; - } - - private List createEntriesList(QueueEntry... entries) - { - ArrayList entriesList = new ArrayList(); - for (QueueEntry entry : entries) - { - entriesList.add(entry.getMessage().getMessageHeader().getMessageId()); - } - return entriesList; - } - - private void verifyReceivedMessages(List expected, - List delivered) - { - assertEquals("Consumer did not receive the expected number of messages", - expected.size(), delivered.size()); - - for (MessageInstance msg : expected) - { - assertTrue("Consumer did not receive msg: " - + msg.getMessage().getMessageNumber(), delivered.contains(msg)); - } - } - - public SimpleAMQQueue getQueue() - { - return _queue; - } - - public MockConsumer getConsumer() - { - return _consumerTarget; - } - - public Map getArguments() - { - return _arguments; - } - - public void setArguments(Map arguments) - { - _arguments = arguments; - } - - - protected ServerMessage createMessage(Long id) throws AMQException - { - AMQMessageHeader header = mock(AMQMessageHeader.class); - when(header.getMessageId()).thenReturn(String.valueOf(id)); - ServerMessage message = mock(ServerMessage.class); - when(message.getMessageNumber()).thenReturn(id); - when(message.getMessageHeader()).thenReturn(header); - - MessageReference ref = mock(MessageReference.class); - when(ref.getMessage()).thenReturn(message); - - - when(message.newReference()).thenReturn(ref); - - return message; - } - - private static class EntryListAddingAction implements Action> - { - private final ArrayList _queueEntries; - - public EntryListAddingAction(final ArrayList queueEntries) - { - _queueEntries = queueEntries; - } - - public void performAction(MessageInstance entry) - { - _queueEntries.add((QueueEntry) entry); - } - } - - class TestSimpleQueueEntryListFactory implements QueueEntryListFactory - { - QueueEntryList _list; - - public QueueEntryList createQueueEntryList(AMQQueue queue) - { - _list = new SimpleQueueEntryList(queue); - return _list; - } - - public QueueEntryList getQueueEntryList() - { - return _list; - } - } -} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTestBase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTestBase.java new file mode 100644 index 0000000000..45001bda50 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTestBase.java @@ -0,0 +1,1184 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInternalException; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.server.exchange.DirectExchange; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.queue.SimpleAMQQueue.QueueEntryFilter; +import org.apache.qpid.server.consumer.MockConsumer; +import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.util.Action; +import org.apache.qpid.server.util.BrokerTestHelper; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.test.utils.QpidTestCase; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +abstract class SimpleAMQQueueTestBase, Q extends SimpleAMQQueue, L extends SimpleQueueEntryList> extends QpidTestCase +{ + private static final Logger _logger = Logger.getLogger(SimpleAMQQueueTestBase.class); + + + private Q _queue; + private VirtualHost _virtualHost; + private String _qname = "qname"; + private String _owner = "owner"; + private String _routingKey = "routing key"; + private DirectExchange _exchange; + private MockConsumer _consumerTarget = new MockConsumer(); + private QueueConsumer _consumer; + private Map _arguments = null; + + @Override + public void setUp() throws Exception + { + super.setUp(); + BrokerTestHelper.setUp(); + + _virtualHost = BrokerTestHelper.createVirtualHost(getClass().getName()); + + _queue = (Q) _virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), _qname, false, _owner, + false, false, false, _arguments); + + _exchange = (DirectExchange) _virtualHost.getExchange(ExchangeDefaults.DIRECT_EXCHANGE_NAME); + } + + @Override + public void tearDown() throws Exception + { + try + { + _queue.stop(); + _virtualHost.close(); + } + finally + { + BrokerTestHelper.tearDown(); + super.tearDown(); + } + } + + public void testCreateQueue() throws AMQException + { + _queue.stop(); + try + { + _queue = (Q) _virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), null, + false, _owner, false, + false, false, _arguments); + assertNull("Queue was created", _queue); + } + catch (IllegalArgumentException e) + { + assertTrue("Exception was not about missing name", + e.getMessage().contains("name")); + } + + _queue = (Q) _virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), + "differentName", false, + _owner, false, + false, false, _arguments); + assertNotNull("Queue was not created", _queue); + } + + + public void testGetVirtualHost() + { + assertEquals("Virtual host was wrong", _virtualHost, _queue.getVirtualHost()); + } + + public void testBinding() throws AMQSecurityException, AMQInternalException + { + _exchange.addBinding(_routingKey, _queue, Collections.EMPTY_MAP); + + assertTrue("Routing key was not bound", + _exchange.isBound(_routingKey)); + assertTrue("Queue was not bound to key", + _exchange.isBound(_routingKey,_queue)); + assertEquals("Exchange binding count", 1, + _queue.getBindings().size()); + assertEquals("Wrong exchange bound", _routingKey, + _queue.getBindings().get(0).getBindingKey()); + assertEquals("Wrong exchange bound", _exchange, + _queue.getBindings().get(0).getExchange()); + + _exchange.removeBinding(_routingKey, _queue, Collections.EMPTY_MAP); + assertFalse("Routing key was still bound", + _exchange.isBound(_routingKey)); + + } + + public void testRegisterConsumerThenEnqueueMessage() throws AMQException + { + ServerMessage messageA = createMessage(new Long(24)); + + // Check adding a consumer adds it to the queue + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + assertEquals("Queue does not have consumer", 1, + _queue.getConsumerCount()); + assertEquals("Queue does not have active consumer", 1, + _queue.getActiveConsumerCount()); + + // Check sending a message ends up with the subscriber + _queue.enqueue(messageA, null); + try + { + Thread.sleep(2000L); + } + catch(InterruptedException e) + { + } + assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage()); + assertNull(_consumer.getQueueContext().getReleasedEntry()); + + // Check removing the consumer removes it's information from the queue + _consumer.close(); + assertTrue("Consumer still had queue", _consumerTarget.isClosed()); + assertFalse("Queue still has consumer", 1 == _queue.getConsumerCount()); + assertFalse("Queue still has active consumer", + 1 == _queue.getActiveConsumerCount()); + + ServerMessage messageB = createMessage(new Long (25)); + _queue.enqueue(messageB, null); + assertNull(_consumer.getQueueContext()); + + } + + public void testEnqueueMessageThenRegisterConsumer() throws AMQException, InterruptedException + { + ServerMessage messageA = createMessage(new Long(24)); + _queue.enqueue(messageA, null); + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + Thread.sleep(150); + assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage()); + assertNull("There should be no releasedEntry after an enqueue", + _consumer.getQueueContext().getReleasedEntry()); + } + + /** + * Tests enqueuing two messages. + */ + public void testEnqueueTwoMessagesThenRegisterConsumer() throws Exception + { + ServerMessage messageA = createMessage(new Long(24)); + ServerMessage messageB = createMessage(new Long(25)); + _queue.enqueue(messageA, null); + _queue.enqueue(messageB, null); + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + Thread.sleep(150); + assertEquals(messageB, _consumer.getQueueContext().getLastSeenEntry().getMessage()); + assertNull("There should be no releasedEntry after enqueues", + _consumer.getQueueContext().getReleasedEntry()); + } + + /** + * Tests that a released queue entry is resent to the subscriber. Verifies also that the + * QueueContext._releasedEntry is reset to null after the entry has been reset. + */ + public void testReleasedMessageIsResentToSubscriber() throws Exception + { + + ServerMessage messageA = createMessage(new Long(24)); + ServerMessage messageB = createMessage(new Long(25)); + ServerMessage messageC = createMessage(new Long(26)); + + + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + final ArrayList queueEntries = new ArrayList(); + EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); + + /* Enqueue three messages */ + + _queue.enqueue(messageA, postEnqueueAction); + _queue.enqueue(messageB, postEnqueueAction); + _queue.enqueue(messageC, postEnqueueAction); + + Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to consumer", + 3, + _consumerTarget.getMessages().size()); + assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); + assertFalse("Redelivery flag should not be set", queueEntries.get(1).isRedelivered()); + assertFalse("Redelivery flag should not be set", queueEntries.get(2).isRedelivered()); + + /* Now release the first message only, causing it to be requeued */ + + queueEntries.get(0).release(); + + Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to consumer", + 4, + _consumerTarget.getMessages().size()); + assertTrue("Redelivery flag should now be set", queueEntries.get(0).isRedelivered()); + assertFalse("Redelivery flag should remain be unset", queueEntries.get(1).isRedelivered()); + assertFalse("Redelivery flag should remain be unset",queueEntries.get(2).isRedelivered()); + assertNull("releasedEntry should be cleared after requeue processed", + _consumer.getQueueContext().getReleasedEntry()); + } + + /** + * Tests that a released message that becomes expired is not resent to the subscriber. + * This tests ensures that SimpleAMQQueueEntry.getNextAvailableEntry avoids expired entries. + * Verifies also that the QueueContext._releasedEntry is reset to null after the entry has been reset. + */ + public void testReleaseMessageThatBecomesExpiredIsNotRedelivered() throws Exception + { + ServerMessage messageA = createMessage(new Long(24)); + + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.SEES_REQUEUES, + Consumer.Option.ACQUIRES)); + + final ArrayList queueEntries = new ArrayList(); + EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); + + /* Enqueue one message with expiration set for a short time in the future */ + + int messageExpirationOffset = 200; + final long expiration = System.currentTimeMillis() + messageExpirationOffset; + when(messageA.getExpiration()).thenReturn(expiration); + + _queue.enqueue(messageA, postEnqueueAction); + + int subFlushWaitTime = 150; + Thread.sleep(subFlushWaitTime); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to consumer", + 1, + _consumerTarget.getMessages().size()); + assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); + + /* Wait a little more to be sure that message will have expired, then release the first message only, causing it to be requeued */ + Thread.sleep(messageExpirationOffset - subFlushWaitTime + 10); + queueEntries.get(0).release(); + + Thread.sleep(subFlushWaitTime); // Work done by SubFlushRunner/QueueRunner Threads + + assertTrue("Expecting the queue entry to be now expired", queueEntries.get(0).expired()); + assertEquals("Total number of messages sent should not have changed", + 1, + _consumerTarget.getMessages().size()); + assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); + assertNull("releasedEntry should be cleared after requeue processed", + _consumer.getQueueContext().getReleasedEntry()); + + } + + /** + * Tests that if a client releases entries 'out of order' (the order + * used by QueueEntryImpl.compareTo) that messages are still resent + * successfully. Specifically this test ensures the {@see SimpleAMQQueue#requeue()} + * can correctly move the _releasedEntry to an earlier position in the QueueEntry list. + */ + public void testReleasedOutOfComparableOrderAreRedelivered() throws Exception + { + + ServerMessage messageA = createMessage(new Long(24)); + ServerMessage messageB = createMessage(new Long(25)); + ServerMessage messageC = createMessage(new Long(26)); + + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + final ArrayList queueEntries = new ArrayList(); + EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); + + /* Enqueue three messages */ + + _queue.enqueue(messageA, postEnqueueAction); + _queue.enqueue(messageB, postEnqueueAction); + _queue.enqueue(messageC, postEnqueueAction); + + Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to consumer", + 3, + _consumerTarget.getMessages().size()); + assertFalse("Redelivery flag should not be set", queueEntries.get(0).isRedelivered()); + assertFalse("Redelivery flag should not be set", queueEntries.get(1).isRedelivered()); + assertFalse("Redelivery flag should not be set", queueEntries.get(2).isRedelivered()); + + /* Now release the third and first message only, causing it to be requeued */ + + queueEntries.get(2).release(); + queueEntries.get(0).release(); + + Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to consumer", + 5, + _consumerTarget.getMessages().size()); + assertTrue("Redelivery flag should now be set", queueEntries.get(0).isRedelivered()); + assertFalse("Redelivery flag should remain be unset", queueEntries.get(1).isRedelivered()); + assertTrue("Redelivery flag should now be set",queueEntries.get(2).isRedelivered()); + assertNull("releasedEntry should be cleared after requeue processed", + _consumer.getQueueContext().getReleasedEntry()); + } + + + /** + * Tests that a release requeues an entry for a queue with multiple consumers. Verifies that a + * requeue resends a message to a single subscriber. + */ + public void testReleaseForQueueWithMultipleConsumers() throws Exception + { + ServerMessage messageA = createMessage(new Long(24)); + ServerMessage messageB = createMessage(new Long(25)); + + MockConsumer target1 = new MockConsumer(); + MockConsumer target2 = new MockConsumer(); + + + QueueConsumer consumer1 = _queue.addConsumer(target1, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + QueueConsumer consumer2 = _queue.addConsumer(target2, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + + final ArrayList queueEntries = new ArrayList(); + EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries); + + /* Enqueue two messages */ + + _queue.enqueue(messageA, postEnqueueAction); + _queue.enqueue(messageB, postEnqueueAction); + + Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to both after enqueue", + 2, + target1.getMessages().size() + target2.getMessages().size()); + + /* Now release the first message only, causing it to be requeued */ + queueEntries.get(0).release(); + + Thread.sleep(150); // Work done by SubFlushRunner/QueueRunner Threads + + assertEquals("Unexpected total number of messages sent to both consumers after release", + 3, + target1.getMessages().size() + target2.getMessages().size()); + assertNull("releasedEntry should be cleared after requeue processed", + consumer1.getQueueContext().getReleasedEntry()); + assertNull("releasedEntry should be cleared after requeue processed", + consumer2.getQueueContext().getReleasedEntry()); + } + + public void testExclusiveConsumer() throws AMQException + { + ServerMessage messageA = createMessage(new Long(24)); + // Check adding an exclusive consumer adds it to the queue + + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.EXCLUSIVE, Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + assertEquals("Queue does not have consumer", 1, + _queue.getConsumerCount()); + assertEquals("Queue does not have active consumer", 1, + _queue.getActiveConsumerCount()); + + // Check sending a message ends up with the subscriber + _queue.enqueue(messageA, null); + try + { + Thread.sleep(2000L); + } + catch (InterruptedException e) + { + } + assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage()); + + // Check we cannot add a second subscriber to the queue + MockConsumer subB = new MockConsumer(); + Exception ex = null; + try + { + + _queue.addConsumer(subB, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + } + catch (AMQException e) + { + ex = e; + } + assertNotNull(ex); + + // Check we cannot add an exclusive subscriber to a queue with an + // existing consumer + _consumer.close(); + _consumer = _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + try + { + + _consumer = _queue.addConsumer(subB, null, messageA.getClass(), "test", + EnumSet.of(Consumer.Option.EXCLUSIVE)); + + } + catch (AMQException e) + { + ex = e; + } + assertNotNull(ex); + } + + + public void testResend() throws Exception + { + Long id = new Long(26); + ServerMessage message = createMessage(id); + + _consumer = _queue.addConsumer(_consumerTarget, null, message.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); + + _queue.enqueue(message, new Action>() + { + @Override + public void performAction(final MessageInstance object) + { + QueueEntryImpl entry = (QueueEntryImpl) object; + entry.setRedelivered(); + try + { + _consumer.resend(entry); + } + catch (AMQException e) + { + fail("Exception thrown: " + e.getMessage()); + } + } + }); + + + + } + + public void testGetFirstMessageId() throws Exception + { + // Create message + Long messageId = new Long(23); + ServerMessage message = createMessage(messageId); + + // Put message on queue + _queue.enqueue(message, null); + // Get message id + Long testmsgid = _queue.getMessagesOnTheQueue(1).get(0); + + // Check message id + assertEquals("Message ID was wrong", messageId, testmsgid); + } + + public void testGetFirstFiveMessageIds() throws Exception + { + for (int i = 0 ; i < 5; i++) + { + // Create message + Long messageId = new Long(i); + ServerMessage message = createMessage(messageId); + // Put message on queue + _queue.enqueue(message, null); + } + // Get message ids + List msgids = _queue.getMessagesOnTheQueue(5); + + // Check message id + for (int i = 0; i < 5; i++) + { + Long messageId = new Long(i); + assertEquals("Message ID was wrong", messageId, msgids.get(i)); + } + } + + public void testGetLastFiveMessageIds() throws Exception + { + for (int i = 0 ; i < 10; i++) + { + // Create message + Long messageId = new Long(i); + ServerMessage message = createMessage(messageId); + // Put message on queue + _queue.enqueue(message, null); + } + // Get message ids + List msgids = _queue.getMessagesOnTheQueue(5, 5); + + // Check message id + for (int i = 0; i < 5; i++) + { + Long messageId = new Long(i+5); + assertEquals("Message ID was wrong", messageId, msgids.get(i)); + } + } + + public void testGetMessagesRangeOnTheQueue() throws Exception + { + for (int i = 1 ; i <= 10; i++) + { + // Create message + Long messageId = new Long(i); + ServerMessage message = createMessage(messageId); + // Put message on queue + _queue.enqueue(message, null); + } + + // Get non-existent 0th QueueEntry & check returned list was empty + // (the position parameters in this method are indexed from 1) + List entries = _queue.getMessagesRangeOnTheQueue(0, 0); + assertTrue(entries.size() == 0); + + // Check that when 'from' is 0 it is ignored and the range continues from 1 + entries = _queue.getMessagesRangeOnTheQueue(0, 2); + assertTrue(entries.size() == 2); + long msgID = entries.get(0).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 1L); + msgID = entries.get(1).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 2L); + + // Check that when 'from' is greater than 'to' the returned list is empty + entries = _queue.getMessagesRangeOnTheQueue(5, 4); + assertTrue(entries.size() == 0); + + // Get first QueueEntry & check id + entries = _queue.getMessagesRangeOnTheQueue(1, 1); + assertTrue(entries.size() == 1); + msgID = entries.get(0).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 1L); + + // Get 5th,6th,7th entries and check id's + entries = _queue.getMessagesRangeOnTheQueue(5, 7); + assertTrue(entries.size() == 3); + msgID = entries.get(0).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 5L); + msgID = entries.get(1).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 6L); + msgID = entries.get(2).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 7L); + + // Get 10th QueueEntry & check id + entries = _queue.getMessagesRangeOnTheQueue(10, 10); + assertTrue(entries.size() == 1); + msgID = entries.get(0).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 10L); + + // Get non-existent 11th QueueEntry & check returned set was empty + entries = _queue.getMessagesRangeOnTheQueue(11, 11); + assertTrue(entries.size() == 0); + + // Get 9th,10th, and non-existent 11th entries & check result is of size 2 with correct IDs + entries = _queue.getMessagesRangeOnTheQueue(9, 11); + assertTrue(entries.size() == 2); + msgID = entries.get(0).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 9L); + msgID = entries.get(1).getMessage().getMessageNumber(); + assertEquals("Message ID was wrong", msgID, 10L); + } + + + /** + * processQueue() is used when asynchronously delivering messages to + * consumers which could not be delivered immediately during the + * enqueue() operation. + * + * A defect within the method would mean that delivery of these messages may + * not occur should the Runner stop before all messages have been processed. + * Such a defect was discovered when Selectors were used such that one and + * only one consumer can/will accept any given messages, but multiple + * consumers are present, and one of the earlier consumers receives + * more messages than the others. + * + * This test is to validate that the processQueue() method is able to + * correctly deliver all of the messages present for asynchronous delivery + * to consumers in such a scenario. + */ + public void testProcessQueueWithUniqueSelectors() throws Exception + { + SimpleAMQQueue testQueue = createNonAsyncDeliverQueue(); + + // retrieve the QueueEntryList the queue creates and insert the test + // messages, thus avoiding straight-through delivery attempts during + //enqueue() process. + QueueEntryList list = testQueue.getEntries(); + assertNotNull("QueueEntryList should have been created", list); + + QueueEntry msg1 = list.add(createMessage(1L)); + QueueEntry msg2 = list.add(createMessage(2L)); + QueueEntry msg3 = list.add(createMessage(3L)); + QueueEntry msg4 = list.add(createMessage(4L)); + QueueEntry msg5 = list.add(createMessage(5L)); + + // Create lists of the entries each consumer should be interested + // in.Bias over 50% of the messages to the first consumer so that + // the later consumers reject them and report being done before + // the first consumer as the processQueue method proceeds. + List msgListSub1 = createEntriesList(msg1, msg2, msg3); + List msgListSub2 = createEntriesList(msg4); + List msgListSub3 = createEntriesList(msg5); + + MockConsumer sub1 = new MockConsumer(msgListSub1); + MockConsumer sub2 = new MockConsumer(msgListSub2); + MockConsumer sub3 = new MockConsumer(msgListSub3); + + // register the consumers + testQueue.addConsumer(sub1, sub1.getFilters(), msg1.getMessage().getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); + testQueue.addConsumer(sub2, sub2.getFilters(), msg1.getMessage().getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); + testQueue.addConsumer(sub3, sub3.getFilters(), msg1.getMessage().getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, Consumer.Option.SEES_REQUEUES)); + + //check that no messages have been delivered to the + //consumers during registration + assertEquals("No messages should have been delivered yet", 0, sub1.getMessages().size()); + assertEquals("No messages should have been delivered yet", 0, sub2.getMessages().size()); + assertEquals("No messages should have been delivered yet", 0, sub3.getMessages().size()); + + // call processQueue to deliver the messages + testQueue.processQueue(new QueueRunner(testQueue) + { + @Override + public void run() + { + // we don't actually want/need this runner to do any work + // because we we are already doing it! + } + }); + + // check expected messages delivered to correct consumers + verifyReceivedMessages(Arrays.asList((MessageInstance)msg1,msg2,msg3), sub1.getMessages()); + verifyReceivedMessages(Collections.singletonList((MessageInstance)msg4), sub2.getMessages()); + verifyReceivedMessages(Collections.singletonList((MessageInstance)msg5), sub3.getMessages()); + } + + private SimpleAMQQueue createNonAsyncDeliverQueue() + { + TestSimpleQueueEntryListFactory factory = new TestSimpleQueueEntryListFactory(); + return new NonAsyncDeliverQueue(factory, getVirtualHost()); + } + + /** + * Tests that dequeued message is not present in the list returned form + * {@link SimpleAMQQueue#getMessagesOnTheQueue()} + */ + public void testGetMessagesOnTheQueueWithDequeuedEntry() + { + int messageNumber = 4; + int dequeueMessageIndex = 1; + + // send test messages into a test queue + enqueueGivenNumberOfMessages(_queue, messageNumber); + + // dequeue message + dequeueMessage(_queue, dequeueMessageIndex); + + // get messages on the queue + List entries = _queue.getMessagesOnTheQueue(); + + // assert queue entries + assertEquals(messageNumber - 1, entries.size()); + int expectedId = 0; + for (int i = 0; i < messageNumber - 1; i++) + { + Long id = ( entries.get(i).getMessage()).getMessageNumber(); + if (i == dequeueMessageIndex) + { + assertFalse("Message with id " + dequeueMessageIndex + + " was dequeued and should not be returned by method getMessagesOnTheQueue!", + new Long(expectedId).equals(id)); + expectedId++; + } + assertEquals("Expected message with id " + expectedId + " but got message with id " + id, + new Long(expectedId), id); + expectedId++; + } + } + + /** + * Tests that dequeued message is not present in the list returned form + * {@link SimpleAMQQueue#getMessagesOnTheQueue(QueueEntryFilter)} + */ + public void testGetMessagesOnTheQueueByQueueEntryFilterWithDequeuedEntry() + { + int messageNumber = 4; + int dequeueMessageIndex = 1; + + // send test messages into a test queue + enqueueGivenNumberOfMessages(_queue, messageNumber); + + // dequeue message + dequeueMessage(_queue, dequeueMessageIndex); + + // get messages on the queue with filter accepting all available messages + List entries = _queue.getMessagesOnTheQueue(new QueueEntryFilter() + { + public boolean accept(E entry) + { + return true; + } + + public boolean filterComplete() + { + return false; + } + }); + + // assert entries on the queue + assertEquals(messageNumber - 1, entries.size()); + int expectedId = 0; + for (int i = 0; i < messageNumber - 1; i++) + { + Long id = (entries.get(i).getMessage()).getMessageNumber(); + if (i == dequeueMessageIndex) + { + assertFalse("Message with id " + dequeueMessageIndex + + " was dequeued and should not be returned by method getMessagesOnTheQueue!", + new Long(expectedId).equals(id)); + expectedId++; + } + assertEquals("Expected message with id " + expectedId + " but got message with id " + id, + new Long(expectedId), id); + expectedId++; + } + } + + + + /** + * Tests that dequeued message on the top is not accounted and next message + * is deleted from the queue on invocation of + * {@link SimpleAMQQueue#deleteMessageFromTop()} + */ + public void testDeleteMessageFromTopWithDequeuedEntryOnTop() + { + int messageNumber = 4; + int dequeueMessageIndex = 0; + + // put messages into a test queue + enqueueGivenNumberOfMessages(_queue, messageNumber); + + // dequeue message on top + dequeueMessage(_queue, dequeueMessageIndex); + + //delete message from top + _queue.deleteMessageFromTop(); + + //get queue entries + List entries = _queue.getMessagesOnTheQueue(); + + // assert queue entries + assertNotNull("Null is returned from getMessagesOnTheQueue", entries); + assertEquals("Expected " + (messageNumber - 2) + " number of messages but recieved " + entries.size(), + messageNumber - 2, entries.size()); + assertEquals("Expected first entry with id 2", 2l, + (entries.get(0).getMessage()).getMessageNumber()); + } + + /** + * Tests that all messages including dequeued one are deleted from the queue + * on invocation of {@link SimpleAMQQueue#clearQueue()} + */ + public void testClearQueueWithDequeuedEntry() + { + int messageNumber = 4; + int dequeueMessageIndex = 1; + + // put messages into a test queue + enqueueGivenNumberOfMessages(_queue, messageNumber); + + // dequeue message on a test queue + dequeueMessage(_queue, dequeueMessageIndex); + + // clean queue + try + { + _queue.clearQueue(); + } + catch (AMQException e) + { + fail("Failure to clear queue:" + e.getMessage()); + } + + // get queue entries + List entries = _queue.getMessagesOnTheQueue(); + + // assert queue entries + assertNotNull(entries); + assertEquals(0, entries.size()); + } + + + public void testNotificationFiredOnEnqueue() throws Exception + { + AMQQueue.NotificationListener listener = mock(AMQQueue.NotificationListener.class); + + _queue.setNotificationListener(listener); + _queue.setMaximumMessageCount(2); + + _queue.enqueue(createMessage(new Long(24)), null); + verifyZeroInteractions(listener); + + _queue.enqueue(createMessage(new Long(25)), null); + + verify(listener, atLeastOnce()).notifyClients(eq(NotificationCheck.MESSAGE_COUNT_ALERT), eq(_queue), contains("Maximum count on queue threshold")); + } + + public void testNotificationFiredAsync() throws Exception + { + AMQQueue.NotificationListener listener = mock(AMQQueue.NotificationListener.class); + + _queue.enqueue(createMessage(new Long(24)), null); + _queue.enqueue(createMessage(new Long(25)), null); + _queue.enqueue(createMessage(new Long(26)), null); + + _queue.setNotificationListener(listener); + _queue.setMaximumMessageCount(2); + + verifyZeroInteractions(listener); + + _queue.checkMessageStatus(); + + verify(listener, atLeastOnce()).notifyClients(eq(NotificationCheck.MESSAGE_COUNT_ALERT), eq(_queue), contains("Maximum count on queue threshold")); + } + + /** + * A helper method to put given number of messages into queue + *

+ * All messages are asserted that they are present on queue + * + * @param queue + * queue to put messages into + * @param messageNumber + * number of messages to put into queue + */ + protected List enqueueGivenNumberOfMessages(Q queue, int messageNumber) + { + putGivenNumberOfMessages(queue, messageNumber); + + // make sure that all enqueued messages are on the queue + List entries = queue.getMessagesOnTheQueue(); + assertEquals(messageNumber, entries.size()); + for (int i = 0; i < messageNumber; i++) + { + assertEquals((long)i, (entries.get(i).getMessage()).getMessageNumber()); + } + return entries; + } + + /** + * A helper method to put given number of messages into queue + *

+ * Queue is not checked if messages are added into queue + * + * @param queue + * queue to put messages into + * @param messageNumber + * number of messages to put into queue + * @param queue + * @param messageNumber + */ + protected void putGivenNumberOfMessages(T queue, int messageNumber) + { + for (int i = 0; i < messageNumber; i++) + { + // Create message + ServerMessage message = null; + try + { + message = createMessage((long)i); + } + catch (AMQException e) + { + fail("Failure to create a test message:" + e.getMessage()); + } + // Put message on queue + try + { + queue.enqueue(message,null); + } + catch (AMQException e) + { + fail("Failure to put message on queue:" + e.getMessage()); + } + } + try + { + Thread.sleep(2000L); + } + catch (InterruptedException e) + { + _logger.error("Thread interrupted", e); + } + } + + /** + * A helper method to dequeue an entry on queue with given index + * + * @param queue + * queue to dequeue message on + * @param dequeueMessageIndex + * entry index to dequeue. + */ + protected QueueEntry dequeueMessage(AMQQueue queue, int dequeueMessageIndex) + { + List entries = queue.getMessagesOnTheQueue(); + QueueEntry entry = entries.get(dequeueMessageIndex); + entry.acquire(); + entry.delete(); + assertTrue(entry.isDeleted()); + return entry; + } + + private List createEntriesList(QueueEntry... entries) + { + ArrayList entriesList = new ArrayList(); + for (QueueEntry entry : entries) + { + entriesList.add(entry.getMessage().getMessageHeader().getMessageId()); + } + return entriesList; + } + + protected void verifyReceivedMessages(List expected, + List delivered) + { + assertEquals("Consumer did not receive the expected number of messages", + expected.size(), delivered.size()); + + for (MessageInstance msg : expected) + { + assertTrue("Consumer did not receive msg: " + + msg.getMessage().getMessageNumber(), delivered.contains(msg)); + } + } + + public Q getQueue() + { + return _queue; + } + + protected void setQueue(Q queue) + { + _queue = queue; + } + + public MockConsumer getConsumer() + { + return _consumerTarget; + } + + public Map getArguments() + { + return _arguments; + } + + public void setArguments(Map arguments) + { + _arguments = arguments; + } + + + protected ServerMessage createMessage(Long id) throws AMQException + { + AMQMessageHeader header = mock(AMQMessageHeader.class); + when(header.getMessageId()).thenReturn(String.valueOf(id)); + ServerMessage message = mock(ServerMessage.class); + when(message.getMessageNumber()).thenReturn(id); + when(message.getMessageHeader()).thenReturn(header); + + MessageReference ref = mock(MessageReference.class); + when(ref.getMessage()).thenReturn(message); + + + when(message.newReference()).thenReturn(ref); + + return message; + } + + private static class EntryListAddingAction implements Action> + { + private final ArrayList _queueEntries; + + public EntryListAddingAction(final ArrayList queueEntries) + { + _queueEntries = queueEntries; + } + + public void performAction(MessageInstance entry) + { + _queueEntries.add((QueueEntry) entry); + } + } + + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public String getQname() + { + return _qname; + } + + public String getOwner() + { + return _owner; + } + + public String getRoutingKey() + { + return _routingKey; + } + + public DirectExchange getExchange() + { + return _exchange; + } + + public MockConsumer getConsumerTarget() + { + return _consumerTarget; + } + + + static class TestSimpleQueueEntryListFactory implements QueueEntryListFactory + { + + @Override + public NonAsyncDeliverList createQueueEntryList(final NonAsyncDeliverQueue queue) + { + return new NonAsyncDeliverList(queue); + } + } + + private static class NonAsyncDeliverEntry extends OrderedQueueEntry + { + + public NonAsyncDeliverEntry(final NonAsyncDeliverList queueEntryList) + { + super(queueEntryList); + } + + public NonAsyncDeliverEntry(final NonAsyncDeliverList queueEntryList, + final ServerMessage message, + final long entryId) + { + super(queueEntryList, message, entryId); + } + + public NonAsyncDeliverEntry(final NonAsyncDeliverList queueEntryList, final ServerMessage message) + { + super(queueEntryList, message); + } + } + + private static class NonAsyncDeliverList extends OrderedQueueEntryList + { + + private static final HeadCreator HEAD_CREATOR = + new HeadCreator() + { + + @Override + public NonAsyncDeliverEntry createHead(final NonAsyncDeliverList list) + { + return new NonAsyncDeliverEntry(list); + } + }; + + public NonAsyncDeliverList(final NonAsyncDeliverQueue queue) + { + super(queue, HEAD_CREATOR); + } + + @Override + protected NonAsyncDeliverEntry createQueueEntry(final ServerMessage message) + { + return new NonAsyncDeliverEntry(this,message); + } + } + + + private static class NonAsyncDeliverQueue extends SimpleAMQQueue + { + public NonAsyncDeliverQueue(final TestSimpleQueueEntryListFactory factory, VirtualHost vhost) + { + super(UUIDGenerator.generateRandomUUID(), + "testQueue", + false, + "testOwner", + false, + false, + vhost, + factory, + null); + } + + @Override + public void deliverAsync(QueueConsumer sub) + { + // do nothing, i.e prevent deliveries by the SubFlushRunner + // when registering the new consumers + } + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java index 11ff7ed192..36425761be 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java @@ -21,8 +21,14 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.UUID; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -30,7 +36,20 @@ import static org.mockito.Mockito.when; public class SimpleQueueEntryImplTest extends QueueEntryImplTestBase { - private SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test")); + private OrderedQueueEntryList queueEntryList; + + @Override + public void setUp() throws Exception + { + mockLogging(); + + StandardQueue queue = new StandardQueue(UUID.randomUUID(), "SimpleQueueEntryImplTest", false, null,false, false, mock(VirtualHost.class),null); + + queueEntryList = queue.getEntries(); + + super.setUp(); + } + public QueueEntryImpl getQueueEntryImpl(int msgId) throws AMQException { diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java deleted file mode 100644 index ae282d5f37..0000000000 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java +++ /dev/null @@ -1,258 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.message.ServerMessage; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SimpleQueueEntryListTest extends QueueEntryListTestBase -{ - private SimpleQueueEntryList _sqel; - - private static final String SCAVENGE_PROP = "qpid.queue.scavenge_count"; - private String oldScavengeValue = null; - - @Override - protected void setUp() - { - oldScavengeValue = System.setProperty(SCAVENGE_PROP, "9"); - _sqel = new SimpleQueueEntryList(_testQueue); - for(int i = 1; i <= 100; i++) - { - final ServerMessage message = mock(ServerMessage.class); - when(message.getMessageNumber()).thenReturn((long) i); - MessageReference ref = mock(MessageReference.class); - when(ref.getMessage()).thenReturn(message); - when(message.newReference()).thenReturn(ref); - - final QueueEntry bleh = _sqel.add(message); - assertNotNull("QE should not have been null", bleh); - } - } - - @Override - protected void tearDown() - { - if(oldScavengeValue != null) - { - System.setProperty(SCAVENGE_PROP, oldScavengeValue); - } - else - { - System.clearProperty(SCAVENGE_PROP); - } - } - - @Override - public QueueEntryList getTestList() - { - return getTestList(false); - } - - @Override - public QueueEntryList getTestList(boolean newList) - { - if(newList) - { - return new SimpleQueueEntryList(_testQueue); - } - else - { - return _sqel; - } - } - - @Override - public long getExpectedFirstMsgId() - { - return 1; - } - - @Override - public int getExpectedListLength() - { - return 100; - } - - @Override - public ServerMessage getTestMessageToAdd() throws AMQException - { - ServerMessage msg = mock(ServerMessage.class); - when(msg.getMessageNumber()).thenReturn(1l); - return msg; - } - - public void testScavenge() throws Exception - { - SimpleQueueEntryList sqel = new SimpleQueueEntryList(null); - ConcurrentHashMap entriesMap = new ConcurrentHashMap(); - - - //Add messages to generate QueueEntry's - for(int i = 1; i <= 100 ; i++) - { - ServerMessage message = mock(ServerMessage.class); - when(message.getMessageNumber()).thenReturn((long) i); - MessageReference ref = mock(MessageReference.class); - when(ref.getMessage()).thenReturn(message); - when(message.newReference()).thenReturn(ref); - QueueEntry bleh = sqel.add(message); - assertNotNull("QE should not have been null", bleh); - entriesMap.put(i,bleh); - } - - SimpleQueueEntryImpl head = sqel.getHead(); - - //We shall now delete some specific messages mid-queue that will lead to - //requiring a scavenge once the requested threshold of 9 deletes is passed - - //Delete the 2nd message only - assertTrue("Failed to delete QueueEntry", remove(entriesMap,2)); - verifyDeletedButPresentBeforeScavenge(head, 2); - - //Delete messages 12 to 14 - assertTrue("Failed to delete QueueEntry", remove(entriesMap,12)); - verifyDeletedButPresentBeforeScavenge(head, 12); - assertTrue("Failed to delete QueueEntry", remove(entriesMap,13)); - verifyDeletedButPresentBeforeScavenge(head, 13); - assertTrue("Failed to delete QueueEntry", remove(entriesMap,14)); - verifyDeletedButPresentBeforeScavenge(head, 14); - - //Delete message 20 only - assertTrue("Failed to delete QueueEntry", remove(entriesMap,20)); - verifyDeletedButPresentBeforeScavenge(head, 20); - - //Delete messages 81 to 84 - assertTrue("Failed to delete QueueEntry", remove(entriesMap,81)); - verifyDeletedButPresentBeforeScavenge(head, 81); - assertTrue("Failed to delete QueueEntry", remove(entriesMap,82)); - verifyDeletedButPresentBeforeScavenge(head, 82); - assertTrue("Failed to delete QueueEntry", remove(entriesMap,83)); - verifyDeletedButPresentBeforeScavenge(head, 83); - assertTrue("Failed to delete QueueEntry", remove(entriesMap,84)); - verifyDeletedButPresentBeforeScavenge(head, 84); - - //Delete message 99 - this is the 10th message deleted that is after the queue head - //and so will invoke the scavenge() which is set to go after 9 previous deletions - assertTrue("Failed to delete QueueEntry", remove(entriesMap,99)); - - verifyAllDeletedMessagedNotPresent(head, entriesMap); - } - - private boolean remove(Map entriesMap, int pos) - { - QueueEntry entry = entriesMap.remove(pos); - boolean wasDeleted = entry.isDeleted(); - entry.delete(); - return entry.isDeleted() && !wasDeleted; - } - - private void verifyDeletedButPresentBeforeScavenge(SimpleQueueEntryImpl head, long messageId) - { - //Use the head to get the initial entry in the queue - SimpleQueueEntryImpl entry = head.getNextNode(); - - for(long i = 1; i < messageId ; i++) - { - assertEquals("Expected QueueEntry was not found in the list", i, (long) entry.getMessage().getMessageNumber()); - entry = entry.getNextNode(); - } - - assertTrue("Entry should have been deleted", entry.isDeleted()); - } - - private void verifyAllDeletedMessagedNotPresent(SimpleQueueEntryImpl head, Map remainingMessages) - { - //Use the head to get the initial entry in the queue - SimpleQueueEntryImpl entry = head.getNextNode(); - - assertNotNull("Initial entry should not have been null", entry); - - int count = 0; - - while (entry != null) - { - assertFalse("Entry " + entry.getMessage().getMessageNumber() + " should not have been deleted", entry.isDeleted()); - assertNotNull("QueueEntry "+entry.getMessage().getMessageNumber()+" was not found in the list of remaining entries " + remainingMessages, - remainingMessages.get((int)(entry.getMessage().getMessageNumber()))); - - count++; - entry = entry.getNextNode(); - } - - assertEquals("Count should have been equal",count,remainingMessages.size()); - } - - public void testGettingNextElement() - { - final int numberOfEntries = 5; - final SimpleQueueEntryImpl[] entries = new SimpleQueueEntryImpl[numberOfEntries]; - final SimpleQueueEntryList queueEntryList = new SimpleQueueEntryList(new MockAMQQueue("test")); - - // create test entries - for(int i = 0; i < numberOfEntries; i++) - { - ServerMessage message = mock(ServerMessage.class); - when(message.getMessageNumber()).thenReturn((long)i); - final MessageReference reference = mock(MessageReference.class); - when(reference.getMessage()).thenReturn(message); - when(message.newReference()).thenReturn(reference); - entries[i] = queueEntryList.add(message); - } - - // test getNext for not acquired entries - for(int i = 0; i < numberOfEntries; i++) - { - final SimpleQueueEntryImpl next = entries[i].getNextValidEntry(); - - if(i < numberOfEntries - 1) - { - assertEquals("Unexpected entry from QueueEntryImpl#getNext()", entries[i + 1], next); - } - else - { - assertNull("The next entry after the last should be null", next); - } - } - - // delete second - entries[1].acquire(); - entries[1].delete(); - - // dequeue third - entries[2].acquire(); - entries[2].delete(); - - SimpleQueueEntryImpl next = entries[2].getNextValidEntry(); - assertEquals("expected forth entry", entries[3], next); - next = next.getNextValidEntry(); - assertEquals("expected fifth entry", entries[4], next); - next = next.getNextValidEntry(); - assertNull("The next entry after the last should be null", next); - } -} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.java deleted file mode 100644 index a84dd6c249..0000000000 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryImplTest.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 java.util.Collections; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.message.AMQMessageHeader; -import org.apache.qpid.server.message.MessageReference; -import org.apache.qpid.server.message.ServerMessage; - -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SortedQueueEntryImplTest extends QueueEntryImplTestBase -{ - - public final static String keys[] = { "CCC", "AAA", "BBB" }; - - private SelfValidatingSortedQueueEntryList queueEntryList = new SelfValidatingSortedQueueEntryList(new MockAMQQueue("test"),"KEY"); - - public QueueEntryImpl getQueueEntryImpl(int msgId) throws AMQException - { - final ServerMessage message = mock(ServerMessage.class); - AMQMessageHeader hdr = mock(AMQMessageHeader.class); - when(message.getMessageHeader()).thenReturn(hdr); - when(hdr.getHeader(eq("KEY"))).thenReturn(keys[msgId-1]); - when(hdr.containsHeader(eq("KEY"))).thenReturn(true); - when(hdr.getHeaderNames()).thenReturn(Collections.singleton("KEY")); - - final MessageReference reference = mock(MessageReference.class); - when(reference.getMessage()).thenReturn(message); - when(message.newReference()).thenReturn(reference); - return queueEntryList.add(message); - } - - public void testCompareTo() - { - assertTrue(_queueEntry.compareTo(_queueEntry2) > 0); - assertTrue(_queueEntry.compareTo(_queueEntry3) > 0); - - assertTrue(_queueEntry2.compareTo(_queueEntry3) < 0); - assertTrue(_queueEntry2.compareTo(_queueEntry) < 0); - - assertTrue(_queueEntry3.compareTo(_queueEntry2) > 0); - assertTrue(_queueEntry3.compareTo(_queueEntry) < 0); - - assertTrue(_queueEntry.compareTo(_queueEntry) == 0); - assertTrue(_queueEntry2.compareTo(_queueEntry2) == 0); - assertTrue(_queueEntry3.compareTo(_queueEntry3) == 0); - } - - public void testTraverseWithNoDeletedEntries() - { - QueueEntry current = _queueEntry2; - - current = current.getNextValidEntry(); - assertSame("Unexpected current entry",_queueEntry3, current); - - current = current.getNextValidEntry(); - assertSame("Unexpected current entry",_queueEntry, current); - - current = current.getNextValidEntry(); - assertNull(current); - - } - - public void testTraverseWithDeletedEntries() - { - // Delete 2nd queue entry - _queueEntry3.delete(); - assertTrue(_queueEntry3.isDeleted()); - - QueueEntry current = _queueEntry2; - - current = current.getNextValidEntry(); - assertSame("Unexpected current entry",_queueEntry, current); - - current = current.getNextValidEntry(); - assertNull(current); - } -} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java index 7add2d4d43..b6b3843ad2 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java @@ -21,20 +21,26 @@ package org.apache.qpid.server.queue; import java.util.Collections; import org.apache.qpid.AMQException; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.logging.actors.CurrentActor; 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.virtualhost.VirtualHost; import java.util.Arrays; +import java.util.UUID; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class SortedQueueEntryListTest extends QueueEntryListTestBase +public class SortedQueueEntryListTest extends QueueEntryListTestBase> { private static SelfValidatingSortedQueueEntryList _sqel; + public final static String keys[] = { " 73", " 18", " 11", "127", "166", "163", " 69", " 60", "191", "144", " 17", "161", "145", "140", "157", " 47", "136", " 56", "176", " 81", "195", " 96", " 2", " 68", "101", "141", "159", "187", "149", " 45", @@ -62,16 +68,30 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase private final static String keysSorted[] = keys.clone(); + private SortedQueue _testQueue; + @Override protected void setUp() throws Exception { + mockLogging(); + + // Create test list + _testQueue = new SortedQueue(UUID.randomUUID(), getName(), false, null, false,false, mock(VirtualHost.class), null, "KEY", new QueueEntryListFactory() + { + + @Override + public SortedQueueEntryList createQueueEntryList(final SortedQueue queue) + { + return new SelfValidatingSortedQueueEntryList(queue, "KEY"); + } + }); + _sqel = (SelfValidatingSortedQueueEntryList) _testQueue.getEntries(); + super.setUp(); // Create result array Arrays.sort(keysSorted); - // Create test list - _sqel = new SelfValidatingSortedQueueEntryList(_testQueue, "KEY"); // Build test list long messageId = 0L; @@ -83,14 +103,22 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase } + protected void mockLogging() + { + final LogActor logActor = mock(LogActor.class); + when(logActor.getRootMessageLogger()).thenReturn(mock(RootMessageLogger.class)); + CurrentActor.setDefault(logActor); + } + + @Override - public QueueEntryList getTestList() + public SortedQueueEntryList getTestList() { return getTestList(false); } @Override - public QueueEntryList getTestList(boolean newList) + public SortedQueueEntryList getTestList(boolean newList) { if(newList) { @@ -117,6 +145,12 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase return generateTestMessage(1, "test value"); } + @Override + protected SortedQueue getTestQueue() + { + return _testQueue; + } + private ServerMessage generateTestMessage(final long id, final String keyValue) throws AMQException { final ServerMessage message = mock(ServerMessage.class); @@ -138,7 +172,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase super.testIterator(); // Test sorted order of list - final QueueEntryIterator iter = getTestList().iterator(); + final QueueEntryIterator> iter = getTestList().iterator(); int count = 0; while(iter.advance()) { @@ -147,12 +181,12 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase } } - private Object getSortedKeyValue(QueueEntryIterator iter) + private Object getSortedKeyValue(QueueEntryIterator> iter) { return (iter.getNode()).getMessage().getMessageHeader().getHeader("KEY"); } - private Long getMessageId(QueueEntryIterator iter) + private Long getMessageId(QueueEntryIterator> iter) { return (iter.getNode()).getMessage().getMessageNumber(); } @@ -169,7 +203,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase _sqel.add(msg); } - final QueueEntryIterator iter = getTestList().iterator(); + final QueueEntryIterator> iter = getTestList().iterator(); int count=0; while(iter.advance()) { @@ -190,12 +224,13 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase _sqel.add(msg); } - final QueueEntryIterator iter = getTestList().iterator(); + final QueueEntryIterator> iter = getTestList().iterator(); int count=0; while(iter.advance()) { assertNull("Sorted queue entry value is not as expected", getSortedKeyValue(iter)); - assertEquals("Message id not as expected", Long.valueOf(count++), getMessageId(iter)); } + assertEquals("Message id not as expected", Long.valueOf(count++), getMessageId(iter)); + } } public void testAscendingSortKeys() throws Exception @@ -211,7 +246,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase _sqel.add(msg); } - final QueueEntryIterator iter = getTestList().iterator(); + final QueueEntryIterator> iter = getTestList().iterator(); int count=0; while(iter.advance()) { @@ -234,7 +269,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase _sqel.add(msg); } - final QueueEntryIterator iter = getTestList().iterator(); + final QueueEntryIterator> iter = getTestList().iterator(); int count=0; while(iter.advance()) { @@ -251,7 +286,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase ServerMessage msg = generateTestMessage(1, "A"); _sqel.add(msg); - SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead()); + SortedQueueEntry entry = _sqel.next(_sqel.getHead()); validateEntry(entry, "A", 1); msg = generateTestMessage(2, "B"); @@ -271,7 +306,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase ServerMessage msg = generateTestMessage(1, "B"); _sqel.add(msg); - SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead()); + SortedQueueEntry entry = _sqel.next(_sqel.getHead()); validateEntry(entry, "B", 1); msg = generateTestMessage(2, "A"); @@ -290,7 +325,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase ServerMessage msg = generateTestMessage(1, "A"); _sqel.add(msg); - SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead()); + SortedQueueEntry entry = _sqel.next(_sqel.getHead()); validateEntry(entry, "A", 1); msg = generateTestMessage(2, "C"); @@ -322,7 +357,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase ServerMessage msg = generateTestMessage(1, "B"); _sqel.add(msg); - SortedQueueEntryImpl entry = _sqel.next(_sqel.getHead()); + SortedQueueEntry entry = _sqel.next(_sqel.getHead()); validateEntry(entry, "B", 1); msg = generateTestMessage(2, "D"); @@ -362,7 +397,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase validateEntry(entry, "D", 2); } - private void validateEntry(final SortedQueueEntryImpl entry, final String expectedSortKey, final long expectedMessageId) + private void validateEntry(final SortedQueueEntry entry, final String expectedSortKey, final long expectedMessageId) { assertEquals("Sorted queue entry value is not as expected", expectedSortKey, entry.getMessage().getMessageHeader().getHeader("KEY")); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java new file mode 100644 index 0000000000..a406c1c26f --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.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.queue; + +import java.util.Collections; +import java.util.UUID; + +import org.apache.qpid.AMQException; +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.virtualhost.VirtualHost; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SortedQueueEntryTest extends QueueEntryImplTestBase +{ + + public final static String keys[] = { "CCC", "AAA", "BBB" }; + + private SelfValidatingSortedQueueEntryList _queueEntryList; + + @Override + public void setUp() throws Exception + { + mockLogging(); + SortedQueue queue = new SortedQueue(UUID.randomUUID(), getName(), false, null, false,false, mock(VirtualHost.class), null, "KEY", new QueueEntryListFactory() + { + + @Override + public SortedQueueEntryList createQueueEntryList(final SortedQueue queue) + { + return new SelfValidatingSortedQueueEntryList(queue, "KEY"); + } + }); + _queueEntryList = (SelfValidatingSortedQueueEntryList) queue.getEntries(); + super.setUp(); + } + + public QueueEntryImpl getQueueEntryImpl(int msgId) throws AMQException + { + final ServerMessage message = mock(ServerMessage.class); + AMQMessageHeader hdr = mock(AMQMessageHeader.class); + when(message.getMessageHeader()).thenReturn(hdr); + when(hdr.getHeader(eq("KEY"))).thenReturn(keys[msgId-1]); + when(hdr.containsHeader(eq("KEY"))).thenReturn(true); + when(hdr.getHeaderNames()).thenReturn(Collections.singleton("KEY")); + + final MessageReference reference = mock(MessageReference.class); + when(reference.getMessage()).thenReturn(message); + when(message.newReference()).thenReturn(reference); + return _queueEntryList.add(message); + } + + public void testCompareTo() + { + assertTrue(_queueEntry.compareTo(_queueEntry2) > 0); + assertTrue(_queueEntry.compareTo(_queueEntry3) > 0); + + assertTrue(_queueEntry2.compareTo(_queueEntry3) < 0); + assertTrue(_queueEntry2.compareTo(_queueEntry) < 0); + + assertTrue(_queueEntry3.compareTo(_queueEntry2) > 0); + assertTrue(_queueEntry3.compareTo(_queueEntry) < 0); + + assertTrue(_queueEntry.compareTo(_queueEntry) == 0); + assertTrue(_queueEntry2.compareTo(_queueEntry2) == 0); + assertTrue(_queueEntry3.compareTo(_queueEntry3) == 0); + } + + public void testTraverseWithNoDeletedEntries() + { + QueueEntry current = _queueEntry2; + + current = current.getNextValidEntry(); + assertSame("Unexpected current entry",_queueEntry3, current); + + current = current.getNextValidEntry(); + assertSame("Unexpected current entry",_queueEntry, current); + + current = current.getNextValidEntry(); + assertNull(current); + + } + + public void testTraverseWithDeletedEntries() + { + // Delete 2nd queue entry + _queueEntry3.delete(); + assertTrue(_queueEntry3.isDeleted()); + + QueueEntry current = _queueEntry2; + + current = current.getNextValidEntry(); + assertSame("Unexpected current entry",_queueEntry, current); + + current = current.getNextValidEntry(); + assertNull(current); + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java new file mode 100644 index 0000000000..c053957e2a --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.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.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class StandardQueueEntryListTest extends QueueEntryListTestBase> +{ + + private StandardQueue _testQueue; + private StandardQueueEntryList _sqel; + + private static final String SCAVENGE_PROP = "qpid.queue.scavenge_count"; + private String oldScavengeValue = null; + + @Override + protected void setUp() + { + oldScavengeValue = System.setProperty(SCAVENGE_PROP, "9"); + _testQueue = new StandardQueue(UUID.randomUUID(),getName(),false,null,false,false,mock(VirtualHost.class), + Collections.emptyMap()); + + _sqel = _testQueue.getEntries(); + for(int i = 1; i <= 100; i++) + { + final ServerMessage message = mock(ServerMessage.class); + when(message.getMessageNumber()).thenReturn((long) i); + MessageReference ref = mock(MessageReference.class); + when(ref.getMessage()).thenReturn(message); + when(message.newReference()).thenReturn(ref); + + final QueueEntry bleh = _sqel.add(message); + assertNotNull("QE should not have been null", bleh); + } + } + + @Override + protected void tearDown() + { + if(oldScavengeValue != null) + { + System.setProperty(SCAVENGE_PROP, oldScavengeValue); + } + else + { + System.clearProperty(SCAVENGE_PROP); + } + } + + @Override + public StandardQueueEntryList getTestList() + { + return getTestList(false); + } + + @Override + public StandardQueueEntryList getTestList(boolean newList) + { + if(newList) + { + StandardQueue queue = + new StandardQueue(UUID.randomUUID(), getName(), false, null, false, false, mock(VirtualHost.class), + Collections.emptyMap()); + + return queue.getEntries(); + } + else + { + return _sqel; + } + } + + @Override + public long getExpectedFirstMsgId() + { + return 1; + } + + @Override + public int getExpectedListLength() + { + return 100; + } + + @Override + public ServerMessage getTestMessageToAdd() throws AMQException + { + ServerMessage msg = mock(ServerMessage.class); + when(msg.getMessageNumber()).thenReturn(1l); + return msg; + } + + @Override + protected StandardQueue getTestQueue() + { + return _testQueue; + } + + public void testScavenge() throws Exception + { + OrderedQueueEntryList sqel = new StandardQueueEntryList(null); + ConcurrentHashMap entriesMap = new ConcurrentHashMap(); + + + //Add messages to generate QueueEntry's + for(int i = 1; i <= 100 ; i++) + { + ServerMessage message = mock(ServerMessage.class); + when(message.getMessageNumber()).thenReturn((long) i); + MessageReference ref = mock(MessageReference.class); + when(ref.getMessage()).thenReturn(message); + when(message.newReference()).thenReturn(ref); + QueueEntry bleh = sqel.add(message); + assertNotNull("QE should not have been null", bleh); + entriesMap.put(i,bleh); + } + + OrderedQueueEntry head = sqel.getHead(); + + //We shall now delete some specific messages mid-queue that will lead to + //requiring a scavenge once the requested threshold of 9 deletes is passed + + //Delete the 2nd message only + assertTrue("Failed to delete QueueEntry", remove(entriesMap,2)); + verifyDeletedButPresentBeforeScavenge(head, 2); + + //Delete messages 12 to 14 + assertTrue("Failed to delete QueueEntry", remove(entriesMap,12)); + verifyDeletedButPresentBeforeScavenge(head, 12); + assertTrue("Failed to delete QueueEntry", remove(entriesMap,13)); + verifyDeletedButPresentBeforeScavenge(head, 13); + assertTrue("Failed to delete QueueEntry", remove(entriesMap,14)); + verifyDeletedButPresentBeforeScavenge(head, 14); + + //Delete message 20 only + assertTrue("Failed to delete QueueEntry", remove(entriesMap,20)); + verifyDeletedButPresentBeforeScavenge(head, 20); + + //Delete messages 81 to 84 + assertTrue("Failed to delete QueueEntry", remove(entriesMap,81)); + verifyDeletedButPresentBeforeScavenge(head, 81); + assertTrue("Failed to delete QueueEntry", remove(entriesMap,82)); + verifyDeletedButPresentBeforeScavenge(head, 82); + assertTrue("Failed to delete QueueEntry", remove(entriesMap,83)); + verifyDeletedButPresentBeforeScavenge(head, 83); + assertTrue("Failed to delete QueueEntry", remove(entriesMap,84)); + verifyDeletedButPresentBeforeScavenge(head, 84); + + //Delete message 99 - this is the 10th message deleted that is after the queue head + //and so will invoke the scavenge() which is set to go after 9 previous deletions + assertTrue("Failed to delete QueueEntry", remove(entriesMap,99)); + + verifyAllDeletedMessagedNotPresent(head, entriesMap); + } + + private boolean remove(Map entriesMap, int pos) + { + QueueEntry entry = entriesMap.remove(pos); + boolean wasDeleted = entry.isDeleted(); + entry.delete(); + return entry.isDeleted() && !wasDeleted; + } + + private void verifyDeletedButPresentBeforeScavenge(OrderedQueueEntry head, long messageId) + { + //Use the head to get the initial entry in the queue + OrderedQueueEntry entry = head.getNextNode(); + + for(long i = 1; i < messageId ; i++) + { + assertEquals("Expected QueueEntry was not found in the list", i, (long) entry.getMessage().getMessageNumber()); + entry = entry.getNextNode(); + } + + assertTrue("Entry should have been deleted", entry.isDeleted()); + } + + private void verifyAllDeletedMessagedNotPresent(OrderedQueueEntry head, Map remainingMessages) + { + //Use the head to get the initial entry in the queue + OrderedQueueEntry entry = head.getNextNode(); + + assertNotNull("Initial entry should not have been null", entry); + + int count = 0; + + while (entry != null) + { + assertFalse("Entry " + entry.getMessage().getMessageNumber() + " should not have been deleted", entry.isDeleted()); + assertNotNull("QueueEntry "+entry.getMessage().getMessageNumber()+" was not found in the list of remaining entries " + remainingMessages, + remainingMessages.get((int)(entry.getMessage().getMessageNumber()))); + + count++; + entry = entry.getNextNode(); + } + + assertEquals("Count should have been equal",count,remainingMessages.size()); + } + + public void testGettingNextElement() + { + final int numberOfEntries = 5; + final OrderedQueueEntry[] entries = new OrderedQueueEntry[numberOfEntries]; + final OrderedQueueEntryList queueEntryList = getTestList(true); + + // create test entries + for(int i = 0; i < numberOfEntries; i++) + { + ServerMessage message = mock(ServerMessage.class); + when(message.getMessageNumber()).thenReturn((long)i); + final MessageReference reference = mock(MessageReference.class); + when(reference.getMessage()).thenReturn(message); + when(message.newReference()).thenReturn(reference); + entries[i] = queueEntryList.add(message); + } + + // test getNext for not acquired entries + for(int i = 0; i < numberOfEntries; i++) + { + final OrderedQueueEntry next = entries[i].getNextValidEntry(); + + if(i < numberOfEntries - 1) + { + assertEquals("Unexpected entry from QueueEntryImpl#getNext()", entries[i + 1], next); + } + else + { + assertNull("The next entry after the last should be null", next); + } + } + + // delete second + entries[1].acquire(); + entries[1].delete(); + + // dequeue third + entries[2].acquire(); + entries[2].delete(); + + OrderedQueueEntry next = entries[2].getNextValidEntry(); + assertEquals("expected forth entry", entries[3], next); + next = next.getNextValidEntry(); + assertEquals("expected fifth entry", entries[4], next); + next = next.getNextValidEntry(); + assertNull("The next entry after the last should be null", next); + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java new file mode 100644 index 0000000000..081b1d30ad --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.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.server.queue; + + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.consumer.ConsumerTarget; +import org.apache.qpid.server.consumer.MockConsumer; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class StandardQueueTest extends SimpleAMQQueueTestBase +{ + + public void testCreationFailsWithNoVhost() + { + try + { + setQueue(new StandardQueue(UUIDGenerator.generateRandomUUID(), getQname(), false, getOwner(), false,false, null, getArguments())); + assertNull("Queue was created", getQueue()); + } + catch (IllegalArgumentException e) + { + assertTrue("Exception was not about missing vhost", + e.getMessage().contains("Host")); + } + } + + + public void testAutoDeleteQueue() throws Exception + { + getQueue().stop(); + setQueue(new StandardQueue(UUIDGenerator.generateRandomUUID(), getQname(), false, null, true, false, getVirtualHost(), Collections.emptyMap())); + getQueue().setDeleteOnNoConsumers(true); + + ServerMessage message = createMessage(25l); + QueueConsumer consumer = + getQueue().addConsumer(getConsumerTarget(), null, message.getClass(), "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + getQueue().enqueue(message, null); + consumer.close(); + assertTrue("Queue was not deleted when consumer was removed", + getQueue().isDeleted()); + } + + public void testActiveConsumerCount() throws Exception + { + final StandardQueue queue = new StandardQueue(UUIDGenerator.generateRandomUUID(), "testActiveConsumerCount", false, + "testOwner", false, false, getVirtualHost(), null); + + //verify adding an active consumer increases the count + final MockConsumer consumer1 = new MockConsumer(); + consumer1.setActive(true); + consumer1.setState(ConsumerTarget.State.ACTIVE); + assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); + queue.addConsumer(consumer1, + null, + createMessage(-1l).getClass(), + "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + + //verify adding an inactive consumer doesn't increase the count + final MockConsumer consumer2 = new MockConsumer(); + consumer2.setActive(false); + consumer2.setState(ConsumerTarget.State.SUSPENDED); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + queue.addConsumer(consumer2, + null, + createMessage(-1l).getClass(), + "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + + //verify behaviour in face of expected state changes: + + //verify a consumer going suspended->active increases the count + consumer2.setState(ConsumerTarget.State.ACTIVE); + assertEquals("Unexpected active consumer count", 2, queue.getActiveConsumerCount()); + + //verify a consumer going active->suspended decreases the count + consumer2.setState(ConsumerTarget.State.SUSPENDED); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + + //verify a consumer going suspended->closed doesn't change the count + consumer2.setState(ConsumerTarget.State.CLOSED); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + + //verify a consumer going active->active doesn't change the count + consumer1.setState(ConsumerTarget.State.ACTIVE); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + + consumer1.setState(ConsumerTarget.State.SUSPENDED); + assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); + + //verify a consumer going suspended->suspended doesn't change the count + consumer1.setState(ConsumerTarget.State.SUSPENDED); + assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); + + consumer1.setState(ConsumerTarget.State.ACTIVE); + assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); + + //verify a consumer going active->closed decreases the count + consumer1.setState(ConsumerTarget.State.CLOSED); + assertEquals("Unexpected active consumer count", 0, queue.getActiveConsumerCount()); + + } + + + /** + * Tests that entry in dequeued state are not enqueued and not delivered to consumer + */ + public void testEnqueueDequeuedEntry() + { + // create a queue where each even entry is considered a dequeued + SimpleAMQQueue queue = new DequeuedQueue(UUIDGenerator.generateRandomUUID(), "test", false, + "testOwner", false, false, getVirtualHost(), null); + // create a consumer + MockConsumer consumer = new MockConsumer(); + + // register consumer + try + { + queue.addConsumer(consumer, + null, + createMessage(-1l).getClass(), + "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + } + catch (AMQException e) + { + fail("Failure to register consumer:" + e.getMessage()); + } + + // put test messages into a queue + putGivenNumberOfMessages(queue, 4); + + // assert received messages + List messages = consumer.getMessages(); + assertEquals("Only 2 messages should be returned", 2, messages.size()); + assertEquals("ID of first message should be 1", 1l, + (messages.get(0).getMessage()).getMessageNumber()); + assertEquals("ID of second message should be 3", 3l, + (messages.get(1).getMessage()).getMessageNumber()); + } + + /** + * Tests whether dequeued entry is sent to subscriber in result of + * invocation of {@link SimpleAMQQueue#processQueue(QueueRunner)} + */ + public void testProcessQueueWithDequeuedEntry() + { + // total number of messages to send + int messageNumber = 4; + int dequeueMessageIndex = 1; + + // create queue with overridden method deliverAsync + StandardQueue testQueue = new StandardQueue(UUIDGenerator.generateRandomUUID(), "test", + false, "testOwner", false, false, getVirtualHost(), null) + { + @Override + public void deliverAsync(QueueConsumer sub) + { + // do nothing + } + }; + + // put messages + List entries = enqueueGivenNumberOfMessages(testQueue, messageNumber); + + // dequeue message + dequeueMessage(testQueue, dequeueMessageIndex); + + // latch to wait for message receipt + final CountDownLatch latch = new CountDownLatch(messageNumber -1); + + // create a consumer + MockConsumer consumer = new MockConsumer() + { + /** + * Send a message and decrement latch + * @param entry + * @param batch + */ + public void send(MessageInstance entry, boolean batch) throws AMQException + { + super.send(entry, batch); + latch.countDown(); + } + }; + + try + { + // subscribe + testQueue.addConsumer(consumer, + null, + entries.get(0).getMessage().getClass(), + "test", + EnumSet.of(Consumer.Option.ACQUIRES, + Consumer.Option.SEES_REQUEUES)); + + // process queue + testQueue.processQueue(new QueueRunner(testQueue) + { + public void run() + { + // do nothing + } + }); + } + catch (AMQException e) + { + fail("Failure to process queue:" + e.getMessage()); + } + // wait up to 1 minute for message receipt + try + { + latch.await(1, TimeUnit.MINUTES); + } + catch (InterruptedException e1) + { + Thread.currentThread().interrupt(); + } + List expected = Arrays.asList((MessageInstance) entries.get(0), entries.get(2), entries.get(3)); + verifyReceivedMessages(expected, consumer.getMessages()); + } + + + private static class DequeuedQueue extends SimpleAMQQueue + { + + public DequeuedQueue(final UUID id, + final String queueName, + final boolean durable, + final String owner, + final boolean autoDelete, + final boolean exclusive, + final VirtualHost virtualHost, + final Map arguments) + { + super(id, queueName, durable, owner, autoDelete, exclusive, virtualHost, new DequeuedQueueEntryListFactory(), arguments); + } + } + private static class DequeuedQueueEntryListFactory implements QueueEntryListFactory + { + public DequeuedQueueEntryList createQueueEntryList(DequeuedQueue queue) + { + /** + * Override SimpleQueueEntryList to create a dequeued + * entries for messages with even id + */ + return new DequeuedQueueEntryList(queue); + } + + + } + + private static class DequeuedQueueEntryList extends OrderedQueueEntryList + { + private static final HeadCreator HEAD_CREATOR = + new HeadCreator() + { + + @Override + public DequeuedQueueEntry createHead(final DequeuedQueueEntryList list) + { + return new DequeuedQueueEntry(list); + } + }; + + public DequeuedQueueEntryList(final DequeuedQueue queue) + { + super(queue, HEAD_CREATOR); + } + + /** + * Entries with even message id are considered + * dequeued! + */ + protected DequeuedQueueEntry createQueueEntry(final ServerMessage message) + { + return new DequeuedQueueEntry(this, message); + } + + + } + + private static class DequeuedQueueEntry extends OrderedQueueEntry + { + + private final ServerMessage _message; + + private DequeuedQueueEntry(final DequeuedQueueEntryList queueEntryList) + { + super(queueEntryList); + _message = null; + } + + public DequeuedQueueEntry(DequeuedQueueEntryList list, final ServerMessage message) + { + super(list, message); + _message = message; + } + + public boolean isDeleted() + { + return (_message.getMessageNumber() % 2 == 0); + } + + public boolean isAvailable() + { + return !(_message.getMessageNumber() % 2 == 0); + } + + @Override + public boolean acquire(QueueConsumer sub) + { + if(_message.getMessageNumber() % 2 == 0) + { + return false; + } + else + { + return super.acquire(sub); + } + } + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java index 11b9bbe1b4..993e9ee4a8 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java @@ -24,9 +24,9 @@ import org.apache.qpid.server.message.MessageInstance; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MockAMQQueue; -import org.apache.qpid.server.queue.MockQueueEntry; -import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.MockMessageInstance; import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.TransactionLogResource; import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState; import org.apache.qpid.test.utils.QpidTestCase; @@ -385,7 +385,7 @@ public class AutoCommitTransactionTest extends QpidTestCase final AMQQueue queue = createTestAMQQueue(queueDurableFlags[i]); final ServerMessage message = createTestMessage(messagePersistentFlags[i]); - queueEntries.add(new MockQueueEntry() + queueEntries.add(new MockMessageInstance() { @Override @@ -395,7 +395,7 @@ public class AutoCommitTransactionTest extends QpidTestCase } @Override - public AMQQueue getQueue() + public TransactionLogResource getOwningResource() { return queue; } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java index 80e794e0ff..bdfdb55c7e 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java @@ -24,9 +24,9 @@ import org.apache.qpid.server.message.MessageInstance; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MockAMQQueue; -import org.apache.qpid.server.queue.MockQueueEntry; -import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.MockMessageInstance; import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.TransactionLogResource; import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState; import org.apache.qpid.test.utils.QpidTestCase; @@ -609,7 +609,7 @@ public class LocalTransactionTest extends QpidTestCase final AMQQueue queue = createTestAMQQueue(queueDurableFlags[i]); final ServerMessage message = createTestMessage(messagePersistentFlags[i]); - queueEntries.add(new MockQueueEntry() + queueEntries.add(new MockMessageInstance() { @Override @@ -619,7 +619,7 @@ public class LocalTransactionTest extends QpidTestCase } @Override - public AMQQueue getQueue() + public TransactionLogResource getOwningResource() { return queue; } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java index cb1fc2737d..ed1ea01108 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java @@ -44,8 +44,8 @@ import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.actors.TestLogActor; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.SimpleAMQQueue; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.SubjectCreator; import org.apache.qpid.server.stats.StatisticsGatherer; @@ -179,9 +179,9 @@ public class BrokerTestHelper return factory.createExchange("amp.direct", "direct", false, false); } - public static SimpleAMQQueue createQueue(String queueName, VirtualHost virtualHost) throws AMQException + public static AMQQueue createQueue(String queueName, VirtualHost virtualHost) throws AMQException { - SimpleAMQQueue queue = (SimpleAMQQueue) virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), queueName, false, null, + AMQQueue queue = virtualHost.createQueue(UUIDGenerator.generateRandomUUID(), queueName, false, null, false, false, false, Collections.emptyMap()); return queue; } diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_Internal_to_v0_10.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_Internal_to_v0_10.java new file mode 100644 index 0000000000..37bbd810b4 --- /dev/null +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_Internal_to_v0_10.java @@ -0,0 +1,156 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol.v0_10; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.internal.InternalMessage; +import org.apache.qpid.server.plugin.MessageConverter; +import org.apache.qpid.server.store.StoreFuture; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageDeliveryPriority; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.typedmessage.TypedBytesContentReader; +import org.apache.qpid.typedmessage.TypedBytesFormatException; + +import java.io.EOFException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +public class MessageConverter_Internal_to_v0_10 implements MessageConverter +{ + @Override + public Class getInputClass() + { + return InternalMessage.class; + } + + @Override + public Class getOutputClass() + { + return MessageTransferMessage.class; + } + + @Override + public MessageTransferMessage convert(InternalMessage serverMsg, VirtualHost vhost) + { + return new MessageTransferMessage(convertToStoredMessage(serverMsg), null); + } + + private StoredMessage convertToStoredMessage(final InternalMessage serverMsg) + { + final byte[] messageContent = MessageConverter_v0_10.convertToBody(serverMsg.getMessageBody()); + final MessageMetaData_0_10 messageMetaData_0_10 = convertMetaData(serverMsg, + MessageConverter_v0_10.getBodyMimeType( + serverMsg.getMessageBody()), + messageContent.length); + + return new StoredMessage() + { + @Override + public MessageMetaData_0_10 getMetaData() + { + return messageMetaData_0_10; + } + + @Override + public long getMessageNumber() + { + return serverMsg.getMessageNumber(); + } + + @Override + public void addContent(int offsetInMessage, ByteBuffer src) + { + throw new UnsupportedOperationException(); + } + + @Override + public int getContent(int offsetInMessage, ByteBuffer dst) + { + int size = messageContent.length - offsetInMessage; + if(dst.remaining() < size) + { + size = dst.remaining(); + } + ByteBuffer buf = ByteBuffer.wrap(messageContent, offsetInMessage, size); + dst.put(buf); + return size; + } + + @Override + public ByteBuffer getContent(int offsetInMessage, int size) + { + return ByteBuffer.wrap(messageContent, offsetInMessage, size); + } + + @Override + public StoreFuture flushToStore() + { + return StoreFuture.IMMEDIATE_FUTURE; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + + private MessageMetaData_0_10 convertMetaData(ServerMessage serverMsg, final String bodyMimeType, final int size) + { + DeliveryProperties deliveryProps = new DeliveryProperties(); + MessageProperties messageProps = new MessageProperties(); + + + + deliveryProps.setExpiration(serverMsg.getExpiration()); + deliveryProps.setPriority(MessageDeliveryPriority.get(serverMsg.getMessageHeader().getPriority())); + deliveryProps.setRoutingKey(serverMsg.getRoutingKey()); + deliveryProps.setTimestamp(serverMsg.getMessageHeader().getTimestamp()); + + messageProps.setContentEncoding(serverMsg.getMessageHeader().getEncoding()); + messageProps.setContentLength(size); + messageProps.setContentType(bodyMimeType); + if(serverMsg.getMessageHeader().getCorrelationId() != null) + { + messageProps.setCorrelationId(serverMsg.getMessageHeader().getCorrelationId().getBytes()); + } + + Header header = new Header(deliveryProps, messageProps, null); + return new MessageMetaData_0_10(header, size, serverMsg.getArrivalTime()); + } + + + @Override + public String getType() + { + return "Internal to v0-10"; + } +} diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10.java index 5244a7f51b..32ecc6bd0e 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10.java @@ -20,7 +20,14 @@ */ package org.apache.qpid.server.protocol.v0_10; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; + import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.plugin.MessageConverter; import org.apache.qpid.server.store.StoreFuture; @@ -30,9 +37,13 @@ import org.apache.qpid.transport.DeliveryProperties; import org.apache.qpid.transport.Header; import org.apache.qpid.transport.MessageDeliveryPriority; import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.codec.BBEncoder; public class MessageConverter_v0_10 implements MessageConverter { + + public static final Charset UTF_8 = Charset.forName("UTF-8"); + @Override public Class getInputClass() { @@ -129,6 +140,79 @@ public class MessageConverter_v0_10 implements MessageConverter +{ + @Override + public Class getInputClass() + { + return MessageTransferMessage.class; + } + + @Override + public Class getOutputClass() + { + return InternalMessage.class; + } + + @Override + public InternalMessage convert(MessageTransferMessage serverMessage, VirtualHost vhost) + { + final String mimeType = serverMessage.getMessageHeader().getMimeType(); + byte[] data = new byte[(int) serverMessage.getSize()]; + serverMessage.getContent(ByteBuffer.wrap(data), 0); + + Object body = convertMessageBody(mimeType, data); + MessageProperties messageProps = serverMessage.getHeader().getMessageProperties(); + AMQMessageHeader fixedHeader = new DelegatingMessageHeader(serverMessage.getMessageHeader(), messageProps == null ? null : messageProps.getReplyTo()); + return InternalMessage.convert(serverMessage.getMessageNumber(), serverMessage.isPersistent(), fixedHeader, body); + } + + private static class DelegatingMessageHeader implements AMQMessageHeader + { + private final AMQMessageHeader _delegate; + private final ReplyTo _replyTo; + + + private DelegatingMessageHeader(final AMQMessageHeader delegate, final ReplyTo replyTo) + { + _delegate = delegate; + _replyTo = replyTo; + } + + @Override + public String getCorrelationId() + { + return _delegate.getCorrelationId(); + } + + @Override + public long getExpiration() + { + return _delegate.getExpiration(); + } + + @Override + public String getUserId() + { + return _delegate.getUserId(); + } + + @Override + public String getAppId() + { + return _delegate.getAppId(); + } + + @Override + public String getMessageId() + { + return _delegate.getMessageId(); + } + + @Override + public String getMimeType() + { + return _delegate.getMimeType(); + } + + @Override + public String getEncoding() + { + return _delegate.getEncoding(); + } + + @Override + public byte getPriority() + { + return _delegate.getPriority(); + } + + @Override + public long getTimestamp() + { + return _delegate.getTimestamp(); + } + + @Override + public String getType() + { + return _delegate.getType(); + } + + @Override + public String getReplyTo() + { + return _replyTo == null + ? null + : _replyTo.getExchange() == null || _replyTo.getExchange().equals("") + ? _replyTo.getRoutingKey() + : _replyTo.getRoutingKey() == null || _replyTo.getRoutingKey().equals("") + ? _replyTo.getExchange() + : _replyTo.getExchange() + "/" + _replyTo.getRoutingKey(); + } + + @Override + public Object getHeader(final String name) + { + return _delegate.getHeader(name); + } + + @Override + public boolean containsHeaders(final Set names) + { + return _delegate.containsHeaders(names); + } + + @Override + public boolean containsHeader(final String name) + { + return _delegate.containsHeader(name); + } + + @Override + public Collection getHeaderNames() + { + return _delegate.getHeaderNames(); + } + } + + private static Object convertMessageBody(String mimeType, byte[] data) + { + if("text/plain".equals(mimeType) || "text/xml".equals(mimeType)) + { + String text = new String(data); + return text; + } + else if("jms/map-message".equals(mimeType)) + { + TypedBytesContentReader reader = new TypedBytesContentReader(ByteBuffer.wrap(data)); + + LinkedHashMap map = new LinkedHashMap(); + final int entries = reader.readIntImpl(); + for (int i = 0; i < entries; i++) + { + try + { + String propName = reader.readStringImpl(); + Object value = reader.readObject(); + + map.put(propName, value); + } + catch (EOFException e) + { + throw new IllegalArgumentException(e); + } + catch (TypedBytesFormatException e) + { + throw new IllegalArgumentException(e); + } + + } + + return map; + + } + else if("amqp/map".equals(mimeType)) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(data)); + final Map map = decoder.readMap(); + + return map; + + } + else if("amqp/list".equals(mimeType)) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(data)); + return decoder.readList(); + } + else if("jms/stream-message".equals(mimeType)) + { + TypedBytesContentReader reader = new TypedBytesContentReader(ByteBuffer.wrap(data)); + + List list = new ArrayList(); + while (reader.remaining() != 0) + { + try + { + list.add(reader.readObject()); + } + catch (TypedBytesFormatException e) + { + throw new RuntimeException(e); // TODO - Implement + } + catch (EOFException e) + { + throw new RuntimeException(e); // TODO - Implement + } + } + return list; + } + else + { + return data; + + } + } + + @Override + public String getType() + { + return "v0-10 to Internal"; + } +} diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java index 53022c333e..87a02b99c1 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java @@ -928,10 +928,10 @@ public class ServerSession extends Session return getId().compareTo(o.getId()); } - private class CheckCapacityAction implements Action> + private class CheckCapacityAction implements Action> { @Override - public void performAction(final MessageInstance entry) + public void performAction(final MessageInstance entry) { TransactionLogResource queue = entry.getOwningResource(); if(queue instanceof CapacityChecker) diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter index 995b0fabdc..dd115905a4 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter @@ -17,3 +17,5 @@ # under the License. # org.apache.qpid.server.protocol.v0_10.MessageConverter_v0_10 +org.apache.qpid.server.protocol.v0_10.MessageConverter_Internal_to_v0_10 +org.apache.qpid.server.protocol.v0_10.MessageConverter_v0_10_to_Internal diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java index 7e712c8e17..8becdf853b 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java @@ -1202,14 +1202,14 @@ public class AMQChannel implements AMQSessionModel, AsyncAutoCommitTransaction.F } - private class ImmediateAction implements Action> + private class ImmediateAction implements Action> { public ImmediateAction() { } - public void performAction(MessageInstance entry) + public void performAction(MessageInstance entry) { TransactionLogResource queue = entry.getOwningResource(); @@ -1274,10 +1274,10 @@ public class AMQChannel implements AMQSessionModel, AsyncAutoCommitTransaction.F } } - private final class CapacityCheckAction implements Action> + private final class CapacityCheckAction implements Action> { @Override - public void performAction(final MessageInstance entry) + public void performAction(final MessageInstance entry) { TransactionLogResource queue = entry.getOwningResource(); if(queue instanceof CapacityChecker) diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_Internal_to_v0_8.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_Internal_to_v0_8.java new file mode 100644 index 0000000000..b80ad3e7b8 --- /dev/null +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_Internal_to_v0_8.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.protocol.v0_8; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.message.internal.InternalMessage; +import org.apache.qpid.server.plugin.MessageConverter; +import org.apache.qpid.server.store.StoreFuture; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.codec.BBEncoder; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class MessageConverter_Internal_to_v0_8 implements MessageConverter +{ + private static final int BASIC_CLASS_ID = 60; + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + + public Class getInputClass() + { + return InternalMessage.class; + } + + @Override + public Class getOutputClass() + { + return AMQMessage.class; + } + + @Override + public AMQMessage convert(InternalMessage serverMsg, VirtualHost vhost) + { + return new AMQMessage(convertToStoredMessage(serverMsg), null); + } + + private StoredMessage convertToStoredMessage(final InternalMessage serverMsg) + { + final byte[] messageContent = convertToBody(serverMsg.getMessageBody()); + final MessageMetaData messageMetaData_0_8 = convertMetaData(serverMsg, + getBodyMimeType(serverMsg.getMessageBody()), + messageContent.length); + + return new StoredMessage() + { + @Override + public MessageMetaData getMetaData() + { + return messageMetaData_0_8; + } + + @Override + public long getMessageNumber() + { + return serverMsg.getMessageNumber(); + } + + @Override + public void addContent(int offsetInMessage, ByteBuffer src) + { + throw new UnsupportedOperationException(); + } + + @Override + public int getContent(int offsetInMessage, ByteBuffer dst) + { + int size = messageContent.length - offsetInMessage; + if(dst.remaining() < size) + { + size = dst.remaining(); + } + ByteBuffer buf = ByteBuffer.wrap(messageContent, offsetInMessage, size); + dst.put(buf); + return size; + } + + @Override + public ByteBuffer getContent(int offsetInMessage, int size) + { + return ByteBuffer.wrap(messageContent, offsetInMessage, size); + } + + @Override + public StoreFuture flushToStore() + { + return StoreFuture.IMMEDIATE_FUTURE; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + + private MessageMetaData convertMetaData(InternalMessage serverMsg, final String bodyMimeType, final int size) + { + + MessagePublishInfo publishInfo = new MessagePublishInfo() + { + @Override + public AMQShortString getExchange() + { + return null; + } + + @Override + public void setExchange(final AMQShortString amqShortString) + { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isImmediate() + { + return false; + } + + @Override + public boolean isMandatory() + { + return false; + } + + @Override + public AMQShortString getRoutingKey() + { + return null; + } + }; + + + final BasicContentHeaderProperties props = new BasicContentHeaderProperties(); + props.setAppId(serverMsg.getMessageHeader().getAppId()); + props.setContentType(bodyMimeType); + props.setCorrelationId(serverMsg.getMessageHeader().getCorrelationId()); + props.setDeliveryMode(serverMsg.isPersistent() ? BasicContentHeaderProperties.PERSISTENT : BasicContentHeaderProperties.NON_PERSISTENT); + props.setExpiration(serverMsg.getExpiration()); + props.setMessageId(serverMsg.getMessageHeader().getMessageId()); + props.setPriority(serverMsg.getMessageHeader().getPriority()); + props.setReplyTo(serverMsg.getMessageHeader().getReplyTo()); + props.setTimestamp(serverMsg.getMessageHeader().getTimestamp()); + props.setUserId(serverMsg.getMessageHeader().getUserId()); + + Map headerProps = new LinkedHashMap(); + + for(String headerName : serverMsg.getMessageHeader().getHeaderNames()) + { + headerProps.put(headerName, serverMsg.getMessageHeader().getHeader(headerName)); + } + + props.setHeaders(FieldTable.convertToFieldTable(headerProps)); + + final ContentHeaderBody chb = new ContentHeaderBody(props, BASIC_CLASS_ID); + return new MessageMetaData(publishInfo, chb, serverMsg.getArrivalTime()); + } + + + @Override + public String getType() + { + return "Internal to v0-8"; + } + + + public static byte[] convertToBody(Object object) + { + if(object instanceof String) + { + return ((String)object).getBytes(UTF_8); + } + else if(object instanceof byte[]) + { + return (byte[]) object; + } + else if(object instanceof Map) + { + BBEncoder encoder = new BBEncoder(1024); + encoder.writeMap((Map)object); + ByteBuffer buf = encoder.segment(); + int remaining = buf.remaining(); + byte[] data = new byte[remaining]; + buf.get(data); + return data; + + } + else if(object instanceof List) + { + BBEncoder encoder = new BBEncoder(1024); + encoder.writeList((List) object); + ByteBuffer buf = encoder.segment(); + int remaining = buf.remaining(); + byte[] data = new byte[remaining]; + buf.get(data); + return data; + } + else + { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + try + { + ObjectOutputStream os = new ObjectOutputStream(bytesOut); + os.writeObject(object); + return bytesOut.toByteArray(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + } + + public static String getBodyMimeType(Object object) + { + if(object instanceof String) + { + return "text/plain"; + } + else if(object instanceof byte[]) + { + return "application/octet-stream"; + } + else if(object instanceof Map) + { + return "amqp/map"; + } + else if(object instanceof List) + { + return "amqp/list"; + } + else + { + return "application/java-object-stream"; + } + } + +} diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java new file mode 100644 index 0000000000..6076ff66c7 --- /dev/null +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.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.protocol.v0_8; + +import org.apache.qpid.server.message.internal.InternalMessage; +import org.apache.qpid.server.plugin.MessageConverter; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.typedmessage.TypedBytesContentReader; +import org.apache.qpid.typedmessage.TypedBytesFormatException; + +import java.io.EOFException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class MessageConverter_v0_8_to_Internal implements MessageConverter +{ + @Override + public Class getInputClass() + { + return AMQMessage.class; + } + + @Override + public Class getOutputClass() + { + return InternalMessage.class; + } + + @Override + public InternalMessage convert(AMQMessage serverMessage, VirtualHost vhost) + { + final String mimeType = serverMessage.getMessageHeader().getMimeType(); + byte[] data = new byte[(int) serverMessage.getSize()]; + serverMessage.getContent(ByteBuffer.wrap(data), 0); + + Object body = convertMessageBody(mimeType, data); + + return InternalMessage.convert(serverMessage.getMessageNumber(), serverMessage.isPersistent(), serverMessage.getMessageHeader(), body); + } + + private static Object convertMessageBody(String mimeType, byte[] data) + { + if("text/plain".equals(mimeType) || "text/xml".equals(mimeType)) + { + String text = new String(data); + return text; + } + else if("jms/map-message".equals(mimeType)) + { + TypedBytesContentReader reader = new TypedBytesContentReader(ByteBuffer.wrap(data)); + + LinkedHashMap map = new LinkedHashMap(); + final int entries = reader.readIntImpl(); + for (int i = 0; i < entries; i++) + { + try + { + String propName = reader.readStringImpl(); + Object value = reader.readObject(); + + map.put(propName, value); + } + catch (EOFException e) + { + throw new IllegalArgumentException(e); + } + catch (TypedBytesFormatException e) + { + throw new IllegalArgumentException(e); + } + + } + + return map; + + } + else if("amqp/map".equals(mimeType)) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(data)); + final Map map = decoder.readMap(); + + return map; + + } + else if("amqp/list".equals(mimeType)) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(data)); + return decoder.readList(); + } + else if("jms/stream-message".equals(mimeType)) + { + TypedBytesContentReader reader = new TypedBytesContentReader(ByteBuffer.wrap(data)); + + List list = new ArrayList(); + while (reader.remaining() != 0) + { + try + { + list.add(reader.readObject()); + } + catch (TypedBytesFormatException e) + { + throw new RuntimeException(e); // TODO - Implement + } + catch (EOFException e) + { + throw new RuntimeException(e); // TODO - Implement + } + } + return list; + } + else + { + return data; + + } + } + + @Override + public String getType() + { + return "v0-8 to Internal"; + } +} diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter new file mode 100644 index 0000000000..d87bc2566f --- /dev/null +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +org.apache.qpid.server.protocol.v0_8.MessageConverter_Internal_to_v0_8 +org.apache.qpid.server.protocol.v0_8.MessageConverter_v0_8_to_Internal \ No newline at end of file diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AcknowledgeTest.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AcknowledgeTest.java index dded0c70fe..f47525097e 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AcknowledgeTest.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AcknowledgeTest.java @@ -24,7 +24,7 @@ package org.apache.qpid.server.protocol.v0_8; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.SimpleAMQQueue; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.util.BrokerTestHelper; @@ -36,7 +36,7 @@ import java.util.List; public class AcknowledgeTest extends QpidTestCase { private AMQChannel _channel; - private SimpleAMQQueue _queue; + private AMQQueue _queue; private MessageStore _messageStore; private String _queueName; @@ -79,7 +79,7 @@ public class AcknowledgeTest extends QpidTestCase return (InternalTestProtocolSession)_channel.getProtocolSession(); } - private SimpleAMQQueue getQueue() + private AMQQueue getQueue() { return _queue; } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/QueueBrowserUsesNoAckTest.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/QueueBrowserUsesNoAckTest.java index f6376e56c4..dc687e1075 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/QueueBrowserUsesNoAckTest.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/QueueBrowserUsesNoAckTest.java @@ -26,10 +26,8 @@ import org.apache.qpid.exchange.ExchangeDefaults; 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.SimpleAMQQueue; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStore; -import org.apache.qpid.server.consumer.Consumer; import org.apache.qpid.server.util.BrokerTestHelper; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.test.utils.QpidTestCase; @@ -39,7 +37,7 @@ import java.util.List; public class QueueBrowserUsesNoAckTest extends QpidTestCase { private AMQChannel _channel; - private SimpleAMQQueue _queue; + private AMQQueue _queue; private MessageStore _messageStore; private String _queueName; @@ -82,7 +80,7 @@ public class QueueBrowserUsesNoAckTest extends QpidTestCase return (InternalTestProtocolSession)_channel.getProtocolSession(); } - private SimpleAMQQueue getQueue() + private AMQQueue getQueue() { return _queue; } diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_Internal_to_v1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_Internal_to_v1_0.java new file mode 100644 index 0000000000..f02908391a --- /dev/null +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_Internal_to_v1_0.java @@ -0,0 +1,140 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol.v1_0; + +import org.apache.qpid.amqp_1_0.messaging.SectionEncoder; +import org.apache.qpid.amqp_1_0.type.Binary; +import org.apache.qpid.amqp_1_0.type.Section; +import org.apache.qpid.amqp_1_0.type.UnsignedByte; +import org.apache.qpid.amqp_1_0.type.UnsignedInteger; +import org.apache.qpid.amqp_1_0.type.messaging.AmqpValue; +import org.apache.qpid.amqp_1_0.type.messaging.ApplicationProperties; +import org.apache.qpid.amqp_1_0.type.messaging.Data; +import org.apache.qpid.amqp_1_0.type.messaging.Header; +import org.apache.qpid.amqp_1_0.type.messaging.Properties; +import org.apache.qpid.server.message.internal.InternalMessage; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public class MessageConverter_Internal_to_v1_0 extends MessageConverter_to_1_0 +{ + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + + public Class getInputClass() + { + return InternalMessage.class; + } + + + @Override + protected MessageMetaData_1_0 convertMetaData(final InternalMessage serverMessage, + final SectionEncoder sectionEncoder) + { + List

sections = new ArrayList
(3); + Header header = new Header(); + + header.setDurable(serverMessage.isPersistent()); + header.setPriority(UnsignedByte.valueOf(serverMessage.getMessageHeader().getPriority())); + if(serverMessage.getExpiration() != 0l && serverMessage.getArrivalTime() !=0l && serverMessage.getExpiration() >= serverMessage.getArrivalTime()) + { + header.setTtl(UnsignedInteger.valueOf(serverMessage.getExpiration()-serverMessage.getArrivalTime())); + } + + sections.add(header); + + Properties properties = new Properties(); + properties.setCorrelationId(serverMessage.getMessageHeader().getCorrelationId()); + properties.setCreationTime(new Date(serverMessage.getMessageHeader().getTimestamp())); + properties.setMessageId(serverMessage.getMessageHeader().getMessageId()); + final String userId = serverMessage.getMessageHeader().getUserId(); + if(userId != null) + { + properties.setUserId(new Binary(userId.getBytes(UTF_8))); + } + properties.setReplyTo(serverMessage.getMessageHeader().getReplyTo()); + + sections.add(properties); + + if(!serverMessage.getMessageHeader().getHeaderNames().isEmpty()) + { + ApplicationProperties applicationProperties = new ApplicationProperties(serverMessage.getMessageHeader().getHeaderMap() ); + sections.add(applicationProperties); + } + return new MessageMetaData_1_0(sections, sectionEncoder); + + } + + protected Section getBodySection(final InternalMessage serverMessage, final String mimeType) + { + return convertToBody(serverMessage.getMessageBody()); + } + + + @Override + public String getType() + { + return "Internal to v1-0"; + } + + + public Section convertToBody(Object object) + { + if(object instanceof String) + { + return new AmqpValue(object); + } + else if(object instanceof byte[]) + { + return new Data(new Binary((byte[])object)); + } + else if(object instanceof Map) + { + return new AmqpValue(MessageConverter_to_1_0.fixMapValues((Map)object)); + } + else if(object instanceof List) + { + return new AmqpValue(MessageConverter_to_1_0.fixListValues((List)object)); + } + else + { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + try + { + ObjectOutputStream os = new ObjectOutputStream(bytesOut); + os.writeObject(object); + return new Data(new Binary(bytesOut.toByteArray())); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + } + +} diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java index a96d951de6..a8a203b247 100644 --- a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java @@ -156,7 +156,7 @@ public abstract class MessageConverter_to_1_0 implement } } - private static Map fixMapValues(final Map map) + static Map fixMapValues(final Map map) { for(Map.Entry entry : map.entrySet()) { @@ -165,7 +165,7 @@ public abstract class MessageConverter_to_1_0 implement return map; } - private static Object fixValue(final Object value) + static Object fixValue(final Object value) { if(value instanceof byte[]) { @@ -185,7 +185,7 @@ public abstract class MessageConverter_to_1_0 implement } } - private static List fixListValues(final List list) + static List fixListValues(final List list) { ListIterator iterator = list.listIterator(); while(iterator.hasNext()) @@ -198,83 +198,88 @@ public abstract class MessageConverter_to_1_0 implement } private StoredMessage convertServerMessage(final MessageMetaData_1_0 metaData, - final ServerMessage serverMessage, + final M serverMessage, SectionEncoder sectionEncoder) { - final String mimeType = serverMessage.getMessageHeader().getMimeType(); - byte[] data = new byte[(int) serverMessage.getSize()]; - serverMessage.getContent(ByteBuffer.wrap(data), 0); + final String mimeType = serverMessage.getMessageHeader().getMimeType(); + Section bodySection = getBodySection(serverMessage, mimeType); - Section bodySection = convertMessageBody(mimeType, data); + final ByteBuffer allData = encodeConvertedMessage(metaData, bodySection, sectionEncoder); - final ByteBuffer allData = encodeConvertedMessage(metaData, bodySection, sectionEncoder); - - return new StoredMessage() - { - @Override - public MessageMetaData_1_0 getMetaData() - { - return metaData; - } - - @Override - public long getMessageNumber() - { - return serverMessage.getMessageNumber(); - } - - @Override - public void addContent(int offsetInMessage, ByteBuffer src) - { - throw new UnsupportedOperationException(); - } - - @Override - public int getContent(int offsetInMessage, ByteBuffer dst) - { - ByteBuffer buf = allData.duplicate(); - buf.position(offsetInMessage); - buf = buf.slice(); - int size; - if(dst.remaining()() { - size = buf.remaining(); - } - dst.put(buf); - return size; - } - - @Override - public ByteBuffer getContent(int offsetInMessage, int size) - { - ByteBuffer buf = allData.duplicate(); - buf.position(offsetInMessage); - buf = buf.slice(); - if(size < buf.remaining()) - { - buf.limit(size); - } - return buf; - } + @Override + public MessageMetaData_1_0 getMetaData() + { + return metaData; + } + + @Override + public long getMessageNumber() + { + return serverMessage.getMessageNumber(); + } + + @Override + public void addContent(int offsetInMessage, ByteBuffer src) + { + throw new UnsupportedOperationException(); + } + + @Override + public int getContent(int offsetInMessage, ByteBuffer dst) + { + ByteBuffer buf = allData.duplicate(); + buf.position(offsetInMessage); + buf = buf.slice(); + int size; + if(dst.remaining() +{ + + static final AMQPDescribedTypeRegistry TYPE_REGISTRY = AMQPDescribedTypeRegistry.newInstance(); + static + { + TYPE_REGISTRY.registerTransportLayer(); + TYPE_REGISTRY.registerMessagingLayer(); + TYPE_REGISTRY.registerTransactionLayer(); + TYPE_REGISTRY.registerSecurityLayer(); + } + + @Override + public Class getInputClass() + { + return Message_1_0.class; + } + + @Override + public Class getOutputClass() + { + return InternalMessage.class; + } + + @Override + public InternalMessage convert(Message_1_0 serverMessage, VirtualHost vhost) + { + final String mimeType = serverMessage.getMessageHeader().getMimeType(); + + + + + byte[] data = new byte[(int) serverMessage.getSize()]; + serverMessage.getStoredMessage().getContent(0,ByteBuffer.wrap(data)); + + SectionDecoderImpl sectionDecoder = new SectionDecoderImpl(TYPE_REGISTRY); + + try + { + List
sections = sectionDecoder.parseAll(ByteBuffer.wrap(data)); + ListIterator
iterator = sections.listIterator(); + Section previousSection = null; + while(iterator.hasNext()) + { + Section section = iterator.next(); + if(!(section instanceof AmqpValue || section instanceof Data || section instanceof AmqpSequence)) + { + iterator.remove(); + } + else + { + if(previousSection != null && (previousSection.getClass() != section.getClass() || section instanceof AmqpValue)) + { + throw new RuntimeException("Message is badly formed and has multiple body section which are not all Data or not all AmqpSequence"); + } + else + { + previousSection = section; + } + } + } + + Object bodyObject; + + if(sections.isEmpty()) + { + // should actually be illegal + bodyObject = new byte[0]; + } + else + { + Section firstBodySection = sections.get(0); + if(firstBodySection instanceof AmqpValue) + { + bodyObject = fixObject(((AmqpValue)firstBodySection).getValue()); + } + else if(firstBodySection instanceof Data) + { + int totalSize = 0; + for(Section section : sections) + { + totalSize += ((Data)section).getValue().getLength(); + } + byte[] bodyData = new byte[totalSize]; + ByteBuffer buf = ByteBuffer.wrap(bodyData); + for(Section section : sections) + { + buf.put(((Data)section).getValue().asByteBuffer()); + } + bodyObject = bodyData; + } + else + { + ArrayList totalSequence = new ArrayList(); + for(Section section : sections) + { + totalSequence.addAll(((AmqpSequence)section).getValue()); + } + bodyObject = fixObject(totalSequence); + } + } + return InternalMessage.convert(serverMessage.getMessageNumber(), serverMessage.isPersistent(), serverMessage.getMessageHeader(), bodyObject); + + } + catch (AmqpErrorException e) + { + throw new RuntimeException(e); + } + + + + + } + + private Object fixObject(final Object value) + { + if(value instanceof Binary) + { + final Binary binaryValue = (Binary) value; + byte[] data = new byte[binaryValue.getLength()]; + binaryValue.asByteBuffer().get(data); + return data; + } + else if(value instanceof List) + { + List listValue = (List) value; + List fixedValue = new ArrayList(listValue.size()); + for(Object o : listValue) + { + fixedValue.add(fixObject(o)); + } + return fixedValue; + } + else if(value instanceof Map) + { + Map mapValue = (Map) value; + Map fixedValue = new LinkedHashMap(mapValue.size()); + for(Map.Entry entry : mapValue.entrySet()) + { + fixedValue.put(fixObject(entry.getKey()),fixObject(entry.getValue())); + } + return fixedValue; + } + else + { + return value; + } + + } + + private static Object convertMessageBody(String mimeType, byte[] data) + { + if("text/plain".equals(mimeType) || "text/xml".equals(mimeType)) + { + String text = new String(data); + return text; + } + else if("jms/map-message".equals(mimeType)) + { + TypedBytesContentReader reader = new TypedBytesContentReader(ByteBuffer.wrap(data)); + + LinkedHashMap map = new LinkedHashMap(); + final int entries = reader.readIntImpl(); + for (int i = 0; i < entries; i++) + { + try + { + String propName = reader.readStringImpl(); + Object value = reader.readObject(); + + map.put(propName, value); + } + catch (EOFException e) + { + throw new IllegalArgumentException(e); + } + catch (TypedBytesFormatException e) + { + throw new IllegalArgumentException(e); + } + + } + + return map; + + } + else if("amqp/map".equals(mimeType)) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(data)); + final Map map = decoder.readMap(); + + return map; + + } + else if("amqp/list".equals(mimeType)) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(data)); + return decoder.readList(); + } + else if("jms/stream-message".equals(mimeType)) + { + TypedBytesContentReader reader = new TypedBytesContentReader(ByteBuffer.wrap(data)); + + List list = new ArrayList(); + while (reader.remaining() != 0) + { + try + { + list.add(reader.readObject()); + } + catch (TypedBytesFormatException e) + { + throw new RuntimeException(e); // TODO - Implement + } + catch (EOFException e) + { + throw new RuntimeException(e); // TODO - Implement + } + } + return list; + } + else + { + return data; + + } + } + + @Override + public String getType() + { + return "v0-8 to Internal"; + } +} diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java index 9e0327fe76..f796a4b2e3 100644 --- a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java @@ -43,16 +43,7 @@ import org.apache.qpid.amqp_1_0.type.DeliveryState; import org.apache.qpid.amqp_1_0.type.Outcome; import org.apache.qpid.amqp_1_0.type.Symbol; import org.apache.qpid.amqp_1_0.type.UnsignedInteger; -import org.apache.qpid.amqp_1_0.type.messaging.Accepted; -import org.apache.qpid.amqp_1_0.type.messaging.ExactSubjectFilter; -import org.apache.qpid.amqp_1_0.type.messaging.Filter; -import org.apache.qpid.amqp_1_0.type.messaging.MatchingSubjectFilter; -import org.apache.qpid.amqp_1_0.type.messaging.Modified; -import org.apache.qpid.amqp_1_0.type.messaging.NoLocalFilter; -import org.apache.qpid.amqp_1_0.type.messaging.Released; -import org.apache.qpid.amqp_1_0.type.messaging.Source; -import org.apache.qpid.amqp_1_0.type.messaging.StdDistMode; -import org.apache.qpid.amqp_1_0.type.messaging.TerminusDurability; +import org.apache.qpid.amqp_1_0.type.messaging.*; import org.apache.qpid.amqp_1_0.type.transport.AmqpError; import org.apache.qpid.amqp_1_0.type.transport.Detach; import org.apache.qpid.amqp_1_0.type.transport.Error; @@ -391,15 +382,21 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS options.add(Consumer.Option.NO_LOCAL); } - - _consumer.setNoLocal(noLocal); - - try { + final String name; + if(getEndpoint().getTarget() instanceof Target) + { + Target target = (Target) getEndpoint().getTarget(); + name = target.getAddress() == null ? getEndpoint().getName() : target.getAddress(); + } + else + { + name = getEndpoint().getName(); + } _consumer = _queue.addConsumer(_target, messageFilter == null ? null : new SimpleFilterManager(messageFilter), - Message_1_0.class, getEndpoint().getName(), options); + Message_1_0.class, name, options); } catch (AMQException e) { diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter new file mode 100644 index 0000000000..aa24847805 --- /dev/null +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.MessageConverter @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +org.apache.qpid.server.protocol.v1_0.MessageConverter_Internal_to_v1_0 +org.apache.qpid.server.protocol.v1_0.MessageConverter_v1_0_to_Internal \ No newline at end of file diff --git a/qpid/java/broker-plugins/amqp-msg-conv-0-8-to-0-10/src/main/java/org/apache/qpid/server/protocol/converter/v0_8_v0_10/MessageConverter_0_10_to_0_8.java b/qpid/java/broker-plugins/amqp-msg-conv-0-8-to-0-10/src/main/java/org/apache/qpid/server/protocol/converter/v0_8_v0_10/MessageConverter_0_10_to_0_8.java index f1843de8ac..0c83c31ad4 100644 --- a/qpid/java/broker-plugins/amqp-msg-conv-0-8-to-0-10/src/main/java/org/apache/qpid/server/protocol/converter/v0_8_v0_10/MessageConverter_0_10_to_0_8.java +++ b/qpid/java/broker-plugins/amqp-msg-conv-0-8-to-0-10/src/main/java/org/apache/qpid/server/protocol/converter/v0_8_v0_10/MessageConverter_0_10_to_0_8.java @@ -61,7 +61,7 @@ public class MessageConverter_0_10_to_0_8 implements MessageConverter + + + + + + + + + + + + + + diff --git a/qpid/java/broker-plugins/management-amqp/pom.xml b/qpid/java/broker-plugins/management-amqp/pom.xml new file mode 100644 index 0000000000..83873a61f2 --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + + + qpid-parent + org.apache.qpid + 1.0-SNAPSHOT + ../../pom.xml + + + qpid-broker-plugins-management-amqp + 0.28-SNAPSHOT + AMQP Management Protocol Plug-in + AMQP Management broker plug-in + + + + org.apache.qpid + qpid-broker-core + ${project.version} + provided + + + + + + + + diff --git a/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagedEntityType.java b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagedEntityType.java new file mode 100644 index 0000000000..10a16faa56 --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagedEntityType.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.management.amqp; + +import java.util.Arrays; + +class ManagedEntityType +{ + private final String _name; + private final ManagedEntityType[] _parents; + private final String[] _attributes; + private final String[] _operations; + + ManagedEntityType(final String name, + final ManagedEntityType[] parents, + final String[] attributes, + final String[] operations) + { + _name = name; + _parents = parents; + _attributes = attributes; + _operations = operations; + } + + public String getName() + { + return _name; + } + + public ManagedEntityType[] getParents() + { + return _parents; + } + + public String[] getAttributes() + { + return _attributes; + } + + public String[] getOperations() + { + return _operations; + } + + @Override + public String toString() + { + return "ManagedEntityType{" + + "name='" + _name + '\'' + + ", parents=" + Arrays.toString(_parents) + + ", attributes=" + Arrays.toString(_attributes) + + ", operations=" + Arrays.toString(_operations) + + '}'; + } +} diff --git a/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java new file mode 100644 index 0000000000..1c1c72dd0b --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java @@ -0,0 +1,1402 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.amqp; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.consumer.ConsumerTarget; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.Filterable; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.InstanceProperties; +import org.apache.qpid.server.message.MessageDestination; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.MessageSource; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.internal.InternalMessage; +import org.apache.qpid.server.message.internal.InternalMessageHeader; +import org.apache.qpid.server.model.AmqpManagement; +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Model; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.plugin.MessageConverter; +import org.apache.qpid.server.plugin.SystemNodeCreator; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.protocol.MessageConverterRegistry; +import org.apache.qpid.server.security.AuthorizationHolder; +import org.apache.qpid.server.store.StorableMessageMetaData; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.util.Action; +import org.apache.qpid.server.util.StateChangeListener; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import java.nio.charset.Charset; +import java.security.AccessControlException; +import java.text.MessageFormat; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +class ManagementNode implements MessageSource, MessageDestination +{ + + public static final String NAME_ATTRIBUTE = "name"; + public static final String IDENTITY_ATTRIBUTE = "identity"; + public static final String TYPE_ATTRIBUTE = "type"; + public static final String OPERATION_HEADER = "operation"; + public static final String SELF_NODE_NAME = "self"; + public static final String MANAGEMENT_TYPE = "org.amqp.management"; + public static final String GET_TYPES = "GET-TYPES"; + public static final String GET_ATTRIBUTES = "GET-ATTRIBUTES"; + public static final String GET_OPERATIONS = "GET-OPERATIONS"; + public static final String QUERY = "QUERY"; + public static final String ENTITY_TYPES_HEADER = "entityTypes"; + public static final String STATUS_CODE_HEADER = "statusCode"; + public static final int STATUS_CODE_OK = 200; + public static final String ATTRIBUTES_HEADER = "attributes"; + public static final String OFFSET_HEADER = "offset"; + public static final String COUNT_HEADER = "count"; + public static final String MANAGEMENT_NODE_NAME = "$management"; + public static final String CREATE_OPERATION = "CREATE"; + public static final String READ_OPERATION = "READ"; + public static final String UPDATE_OPERATION = "UPDATE"; + public static final String DELETE_OPERATION = "DELETE"; + public static final String STATUS_DESCRIPTION_HEADER = "statusDescription"; + public static final int NOT_FOUND_STATUS_CODE = 404; + public static final int NOT_IMPLEMENTED_STATUS_CODE = 501; + public static final int STATUS_CODE_NO_CONTENT = 204; + public static final int STATUS_CODE_FORBIDDEN = 403; + public static final int STATUS_CODE_BAD_REQUEST = 400; + public static final int STATUS_CODE_INTERNAL_ERROR = 500; + + + private final VirtualHost _virtualHost; + + private final UUID _id; + + private final CopyOnWriteArrayList> _consumerRegistrationListeners = + new CopyOnWriteArrayList>(); + + private final SystemNodeCreator.SystemNodeRegistry _registry; + private final ConfiguredObject _managedObject; + private Map _consumers = new ConcurrentHashMap(); + + private Map _entityTypes = Collections.synchronizedMap(new LinkedHashMap()); + + private Map> _entities = Collections.synchronizedMap(new LinkedHashMap>()); + + + public ManagementNode(final SystemNodeCreator.SystemNodeRegistry registry, + final ConfiguredObject configuredObject) + { + _virtualHost = registry.getVirtualHost(); + _registry = registry; + final String name = configuredObject.getId() + MANAGEMENT_NODE_NAME; + _id = UUID.nameUUIDFromBytes(name.getBytes(Charset.defaultCharset())); + + + _managedObject = configuredObject; + + populateTypeMetaData(configuredObject.getClass(), false); + + configuredObject.addChangeListener(new ModelObjectListener()); + + final Class managementClass = getManagementClass(_managedObject.getClass()); + _entities.get(_entityTypes.get(managementClass.getName())).put(_managedObject.getName(), _managedObject); + + Collection> childClasses = Model.getInstance().getChildTypes(managementClass); + for(Class childClass : childClasses) + { + if(getManagementClass(childClass) != null) + { + for(ConfiguredObject child : _managedObject.getChildren(childClass)) + { + _entities.get(_entityTypes.get(getManagementClass(childClass).getName())).put(child.getName(), child); + } + } + } + + } + + private Class getManagementClass(Class objectClass) + { + List allClasses = new ArrayList(); + allClasses.add(objectClass); + allClasses.addAll(Arrays.asList(objectClass.getInterfaces())); + allClasses.add(objectClass.getSuperclass()); + for(Class clazz : allClasses) + { + AmqpManagement annotation = (AmqpManagement) clazz.getAnnotation(AmqpManagement.class); + if(annotation != null) + { + return clazz; + } + } + return null; + } + + private boolean populateTypeMetaData(final Class objectClass, boolean allowCreate) + { + Class clazz = getManagementClass(objectClass); + if( clazz != null) + { + AmqpManagement annotation = (AmqpManagement) clazz.getAnnotation(AmqpManagement.class); + populateTypeMetaData(clazz, annotation); + return true; + } + else + { + return false; + } + } + + private ManagedEntityType populateTypeMetaData(Class clazz, + final AmqpManagement entityType) + { + + ManagedEntityType managedEntityType = _entityTypes.get(clazz.getName()); + + if(managedEntityType == null) + { + List opsList = new ArrayList(Arrays.asList(entityType.operations())); + if(entityType.creatable()) + { + boolean isCreatableChild = false; + for(Class parentConfig : Model.getInstance().getParentTypes(clazz)) + { + isCreatableChild = parentConfig.isAssignableFrom(_managedObject.getClass()); + if(isCreatableChild) + { + opsList.add(CREATE_OPERATION); + break; + } + } + } + opsList.addAll(Arrays.asList(READ_OPERATION, UPDATE_OPERATION, DELETE_OPERATION)); + + Set parentSet = new HashSet(); + + List allClasses = new ArrayList(Arrays.asList(clazz.getInterfaces())); + if(clazz.getSuperclass() != null) + { + allClasses.add(clazz.getSuperclass()); + } + + for(Class parentClazz : allClasses) + { + if(parentClazz.getAnnotation(AmqpManagement.class) != null) + { + ManagedEntityType parentType = populateTypeMetaData(parentClazz, + (AmqpManagement) parentClazz.getAnnotation( + AmqpManagement.class) + ); + parentSet.add(parentType); + parentSet.addAll(Arrays.asList(parentType.getParents())); + + } + } + managedEntityType = new ManagedEntityType(clazz.getName(), parentSet.toArray(new ManagedEntityType[parentSet.size()]), entityType.attributes(), opsList.toArray(new String[opsList.size()])); + _entityTypes.put(clazz.getName(),managedEntityType); + _entities.put(managedEntityType, Collections.synchronizedMap(new LinkedHashMap())); + + if(ConfiguredObject.class.isAssignableFrom(clazz)) + { + Collection> childTypes = Model.getInstance().getChildTypes(clazz); + for(Class childClass : childTypes) + { + populateTypeMetaData(childClass, true); + } + } + + } + + return managedEntityType; + + } + + @Override + public > int send(final M message, + final InstanceProperties instanceProperties, + final ServerTransaction txn, + final Action> postEnqueueAction) + { + + @SuppressWarnings("unchecked") + MessageConverter converter = + MessageConverterRegistry.getConverter((Class)message.getClass(), InternalMessage.class); + + final InternalMessage msg = converter.convert(message, _virtualHost); + + if(validateMessage(msg)) + { + txn.addPostTransactionAction(new ServerTransaction.Action() + { + @Override + public void postCommit() + { + enqueue(msg, instanceProperties, postEnqueueAction); + } + + @Override + public void onRollback() + { + + } + }); + + return 1; + } + else + { + return 0; + } + } + + private boolean validateMessage(final ServerMessage message) + { + AMQMessageHeader header = message.getMessageHeader(); + return containsStringHeader(header, TYPE_ATTRIBUTE) && containsStringHeader(header, OPERATION_HEADER) + && (containsStringHeader(header, NAME_ATTRIBUTE) || containsStringHeader(header, IDENTITY_ATTRIBUTE)); + } + + private boolean containsStringHeader(final AMQMessageHeader header, String name) + { + return header.containsHeader(name) && header.getHeader(name) instanceof String; + } + + synchronized void enqueue(InternalMessage message, InstanceProperties properties, Action> postEnqueueAction) + { + if(postEnqueueAction != null) + { + postEnqueueAction.performAction(new ConsumedMessageInstance(message, properties)); + } + + + + String name = (String) message.getMessageHeader().getHeader(NAME_ATTRIBUTE); + String id = (String) message.getMessageHeader().getHeader(IDENTITY_ATTRIBUTE); + String type = (String) message.getMessageHeader().getHeader(TYPE_ATTRIBUTE); + String operation = (String) message.getMessageHeader().getHeader(OPERATION_HEADER); + + InternalMessage response; + + if(SELF_NODE_NAME.equals(name) && type.equals(MANAGEMENT_TYPE)) + { + response = performManagementOperation(message); + } + else if(CREATE_OPERATION.equals(operation)) + { + response = performCreateOperation(message, type); + } + else + { + + ConfiguredObject entity = findSubject(name, id, type); + + if(entity != null) + { + response = performOperation(message, entity); + } + else + { + if(id != null) + { + response = createFailureResponse(message, + NOT_FOUND_STATUS_CODE, + "No entity with id {0} of type {1} found", id, type); + } + else + { + response = createFailureResponse(message, + NOT_FOUND_STATUS_CODE, + "No entity with name {0} of type {1} found", name, type); + } + } + } + + + ManagementNodeConsumer consumer = _consumers.get(message.getMessageHeader().getReplyTo()); + if(consumer != null) + { + // TODO - check same owner + consumer.send(response); + } + // TODO - route to a queue + + } + + private InternalMessage performCreateOperation(final InternalMessage message, final String type) + { + InternalMessage response; + ManagedEntityType entityType = _entityTypes.get(type); + if(type != null) + { + if(Arrays.asList(entityType.getOperations()).contains(CREATE_OPERATION)) + { + Object messageBody = message.getMessageBody(); + if(messageBody instanceof Map) + { + try + { + + Class clazz = + (Class) Class.forName(type); + try + { + ConfiguredObject child = _managedObject.createChild(clazz, (Map) messageBody); + if(child == null) + { + child = _entities.get(entityType).get(message.getMessageHeader().getHeader(NAME_ATTRIBUTE)); + } + response = performReadOperation(message, child); + } + catch(RuntimeException e) + { + if (e instanceof AccessControlException || e.getCause() instanceof AMQSecurityException) + { + response = createFailureResponse(message, STATUS_CODE_FORBIDDEN, e.getMessage()); + } + else + { + throw e; + } + } + } + catch (ClassNotFoundException e) + { + response = createFailureResponse(message, + STATUS_CODE_INTERNAL_ERROR, "Unable to instantiate an instance of {0} ", type); + } + } + else + { + response = createFailureResponse(message, + STATUS_CODE_BAD_REQUEST, + "The message body in the request was not of the correct type"); + } + } + else + { + response = createFailureResponse(message, + STATUS_CODE_FORBIDDEN, + "Cannot CREATE entities of type {0}", type); + } + } + else + { + response = createFailureResponse(message, + NOT_FOUND_STATUS_CODE, + "Unknown type {0}",type); + } + return response; + } + + private InternalMessage performOperation(final InternalMessage requestMessage, final ConfiguredObject entity) + { + String operation = (String) requestMessage.getMessageHeader().getHeader(OPERATION_HEADER); + + if(READ_OPERATION.equals(operation)) + { + return performReadOperation(requestMessage, entity); + } + else if(DELETE_OPERATION.equals(operation)) + { + return performDeleteOperation(requestMessage, entity); + } + else if(UPDATE_OPERATION.equals(operation)) + { + return performUpdateOperation(requestMessage, entity); + } + else + { + return createFailureResponse(requestMessage, NOT_IMPLEMENTED_STATUS_CODE, "Unable to perform the {0} operation",operation); + } + } + + private InternalMessage performReadOperation(final InternalMessage requestMessage, final ConfiguredObject entity) + { + final InternalMessageHeader requestHeader = requestMessage.getMessageHeader(); + final MutableMessageHeader responseHeader = new MutableMessageHeader(); + responseHeader.setCorrelationId(requestHeader.getCorrelationId() == null + ? requestHeader.getMessageId() + : requestHeader.getCorrelationId()); + responseHeader.setMessageId(UUID.randomUUID().toString()); + responseHeader.setHeader(NAME_ATTRIBUTE, entity.getName()); + responseHeader.setHeader(IDENTITY_ATTRIBUTE, entity.getId().toString()); + responseHeader.setHeader(STATUS_CODE_HEADER,STATUS_CODE_OK); + final String type = getManagementClass(entity.getClass()).getName(); + responseHeader.setHeader(TYPE_ATTRIBUTE, type); + + Map responseBody = new LinkedHashMap(); + final ManagedEntityType entityType = _entityTypes.get(type); + for(String attribute : entityType.getAttributes()) + { + responseBody.put(attribute, fixValue(entity.getAttribute(attribute))); + } + + return InternalMessage.createMapMessage(_virtualHost.getMessageStore(),responseHeader, responseBody); + } + + + private InternalMessage performDeleteOperation(final InternalMessage requestMessage, final ConfiguredObject entity) + { + final InternalMessageHeader requestHeader = requestMessage.getMessageHeader(); + final MutableMessageHeader responseHeader = new MutableMessageHeader(); + responseHeader.setCorrelationId(requestHeader.getCorrelationId() == null + ? requestHeader.getMessageId() + : requestHeader.getCorrelationId()); + responseHeader.setMessageId(UUID.randomUUID().toString()); + responseHeader.setHeader(NAME_ATTRIBUTE, entity.getName()); + responseHeader.setHeader(IDENTITY_ATTRIBUTE, entity.getId().toString()); + final String type = getManagementClass(entity.getClass()).getName(); + responseHeader.setHeader(TYPE_ATTRIBUTE, type); + try + { + entity.setDesiredState(entity.getActualState(),State.DELETED); + responseHeader.setHeader(STATUS_CODE_HEADER, STATUS_CODE_NO_CONTENT); + } + catch(RuntimeException e) + { + if (e instanceof AccessControlException || e.getCause() instanceof AMQSecurityException) + { + responseHeader.setHeader(STATUS_CODE_HEADER, STATUS_CODE_FORBIDDEN); + } + else + { + throw e; + } + + } + + return InternalMessage.createMapMessage(_virtualHost.getMessageStore(),responseHeader, Collections.emptyMap()); + } + + + private InternalMessage performUpdateOperation(final InternalMessage requestMessage, final ConfiguredObject entity) + { + final InternalMessageHeader requestHeader = requestMessage.getMessageHeader(); + final MutableMessageHeader responseHeader = new MutableMessageHeader(); + responseHeader.setCorrelationId(requestHeader.getCorrelationId() == null + ? requestHeader.getMessageId() + : requestHeader.getCorrelationId()); + responseHeader.setMessageId(UUID.randomUUID().toString()); + responseHeader.setHeader(NAME_ATTRIBUTE, entity.getName()); + responseHeader.setHeader(IDENTITY_ATTRIBUTE, entity.getId().toString()); + final String type = getManagementClass(entity.getClass()).getName(); + responseHeader.setHeader(TYPE_ATTRIBUTE, type); + + Object messageBody = requestMessage.getMessageBody(); + if(messageBody instanceof Map) + { + try + { + entity.setAttributes((Map)messageBody); + return performReadOperation(requestMessage, entity); + } + catch(RuntimeException e) + { + if (e instanceof AccessControlException || e.getCause() instanceof AMQSecurityException) + { + return createFailureResponse(requestMessage, STATUS_CODE_FORBIDDEN, e.getMessage()); + } + else + { + throw e; + } + } + } + else + { + return createFailureResponse(requestMessage, + STATUS_CODE_BAD_REQUEST, + "The message body in the request was not of the correct type"); + } + + + } + + private ConfiguredObject findSubject(final String name, final String id, final String type) + { + ConfiguredObject subject; + ManagedEntityType met = _entityTypes.get(type); + if(met == null) + { + return null; + } + + subject = findSubject(name, id, met); + if(subject == null) + { + ArrayList allTypes = new ArrayList(_entityTypes.values()); + for(ManagedEntityType entityType : allTypes) + { + if(Arrays.asList(entityType.getParents()).contains(met)) + { + subject = findSubject(name, id, entityType); + if(subject != null) + { + return subject; + } + } + } + } + return subject; + } + + private ConfiguredObject findSubject(final String name, final String id, final ManagedEntityType entityType) + { + + Map objects = _entities.get(entityType); + if(name != null) + { + ConfiguredObject subject = objects.get(name); + if(subject != null) + { + return subject; + } + } + else + { + final Collection values = new ArrayList(objects.values()); + for(ConfiguredObject o : values) + { + if(o.getId().toString().equals(id)) + { + return o; + } + } + } + return null; + } + + private InternalMessage createFailureResponse(final InternalMessage requestMessage, + final int statusCode, + final String stateDescription, + String... params) + { + final InternalMessageHeader requestHeader = requestMessage.getMessageHeader(); + final MutableMessageHeader responseHeader = new MutableMessageHeader(); + responseHeader.setCorrelationId(requestHeader.getCorrelationId() == null + ? requestHeader.getMessageId() + : requestHeader.getCorrelationId()); + responseHeader.setMessageId(UUID.randomUUID().toString()); + for(String header : requestHeader.getHeaderNames()) + { + responseHeader.setHeader(header, requestHeader.getHeader(header)); + } + responseHeader.setHeader(STATUS_CODE_HEADER, statusCode); + responseHeader.setHeader(STATUS_DESCRIPTION_HEADER, MessageFormat.format(stateDescription, params)); + return InternalMessage.createBytesMessage(_virtualHost.getMessageStore(), responseHeader, new byte[0]); + + } + + private InternalMessage performManagementOperation(final InternalMessage msg) + { + final InternalMessage responseMessage; + final InternalMessageHeader requestHeader = msg.getMessageHeader(); + final MutableMessageHeader responseHeader = new MutableMessageHeader(); + responseHeader.setCorrelationId(requestHeader.getCorrelationId() == null + ? requestHeader.getMessageId() + : requestHeader.getCorrelationId()); + responseHeader.setMessageId(UUID.randomUUID().toString()); + + + String operation = (String) requestHeader.getHeader(OPERATION_HEADER); + if(GET_TYPES.equals(operation)) + { + responseMessage = performGetTypes(requestHeader, responseHeader); + } + else if(GET_ATTRIBUTES.equals(operation)) + { + responseMessage = performGetAttributes(requestHeader, responseHeader); + } + else if(GET_OPERATIONS.equals(operation)) + { + responseMessage = performGetOperations(requestHeader, responseHeader); + } + else if(QUERY.equals(operation)) + { + responseMessage = performQuery(requestHeader, responseHeader); + } + else + { + responseMessage = InternalMessage.createBytesMessage(_virtualHost.getMessageStore(), requestHeader, new byte[0]); + } + return responseMessage; + } + + private InternalMessage performGetTypes(final InternalMessageHeader requestHeader, + final MutableMessageHeader responseHeader) + { + final InternalMessage responseMessage; + List restriction; + if(requestHeader.containsHeader(ENTITY_TYPES_HEADER)) + { + restriction = (List) requestHeader.getHeader(ENTITY_TYPES_HEADER); + } + else + { + restriction = null; + } + + responseHeader.setHeader(STATUS_CODE_HEADER, STATUS_CODE_OK); + Map responseMap = new LinkedHashMap(); + Map entityMapCopy; + synchronized (_entityTypes) + { + entityMapCopy = new LinkedHashMap(_entityTypes); + } + + for(ManagedEntityType type : entityMapCopy.values()) + { + if(restriction == null || meetsIndirectRestriction(type,restriction)) + { + final ManagedEntityType[] parents = type.getParents(); + List parentNames = new ArrayList(); + if(parents != null) + { + for(ManagedEntityType parent : parents) + { + parentNames.add(parent.getName()); + } + } + responseMap.put(type.getName(), parentNames); + } + } + responseMessage = InternalMessage.createMapMessage(_virtualHost.getMessageStore(), responseHeader, responseMap); + return responseMessage; + } + + private InternalMessage performGetAttributes(final InternalMessageHeader requestHeader, + final MutableMessageHeader responseHeader) + { + final InternalMessage responseMessage; + List restriction; + if(requestHeader.containsHeader(ENTITY_TYPES_HEADER)) + { + restriction = (List) requestHeader.getHeader(ENTITY_TYPES_HEADER); + } + else + { + restriction = null; + } + + responseHeader.setHeader(STATUS_CODE_HEADER, STATUS_CODE_OK); + Map responseMap = new LinkedHashMap(); + Map entityMapCopy; + synchronized (_entityTypes) + { + entityMapCopy = new LinkedHashMap(_entityTypes); + } + + for(ManagedEntityType type : entityMapCopy.values()) + { + if(restriction == null || restriction.contains(type.getName())) + { + responseMap.put(type.getName(), Arrays.asList(type.getAttributes())); + } + } + responseMessage = InternalMessage.createMapMessage(_virtualHost.getMessageStore(), responseHeader, responseMap); + return responseMessage; + } + + + private InternalMessage performGetOperations(final InternalMessageHeader requestHeader, + final MutableMessageHeader responseHeader) + { + final InternalMessage responseMessage; + List restriction; + if(requestHeader.containsHeader(ENTITY_TYPES_HEADER)) + { + restriction = (List) requestHeader.getHeader(ENTITY_TYPES_HEADER); + } + else + { + restriction = null; + } + + responseHeader.setHeader(STATUS_CODE_HEADER, STATUS_CODE_OK); + Map responseMap = new LinkedHashMap(); + Map entityMapCopy; + synchronized (_entityTypes) + { + entityMapCopy = new LinkedHashMap(_entityTypes); + } + + for(ManagedEntityType type : entityMapCopy.values()) + { + if(restriction == null || restriction.contains(type.getName())) + { + responseMap.put(type.getName(), Arrays.asList(type.getOperations())); + } + } + responseMessage = InternalMessage.createMapMessage(_virtualHost.getMessageStore(), responseHeader, responseMap); + return responseMessage; + } + + private InternalMessage performQuery(final InternalMessageHeader requestHeader, + final MutableMessageHeader responseHeader) + { + final InternalMessage responseMessage; + List restriction; + List attributes; + int offset; + int count; + + if(requestHeader.containsHeader(ENTITY_TYPES_HEADER)) + { + restriction = (List) requestHeader.getHeader(ENTITY_TYPES_HEADER); + responseHeader.setHeader(ENTITY_TYPES_HEADER, restriction); + } + else + { + restriction = new ArrayList(_entityTypes.keySet()); + } + + + if(requestHeader.containsHeader(ATTRIBUTES_HEADER)) + { + attributes = (List) requestHeader.getHeader(ATTRIBUTES_HEADER); + } + else + { + LinkedHashMap attributeSet = new LinkedHashMap(); + for(String entityType : restriction) + { + ManagedEntityType type = _entityTypes.get(entityType); + if(type != null) + { + for(String attributeName : type.getAttributes()) + { + attributeSet.put(attributeName, null); + } + } + } + attributes = new ArrayList(attributeSet.keySet()); + + } + + if(requestHeader.containsHeader(OFFSET_HEADER)) + { + offset = ((Number) requestHeader.getHeader(OFFSET_HEADER)).intValue(); + responseHeader.setHeader(OFFSET_HEADER,offset); + } + else + { + offset = 0; + } + + if(requestHeader.containsHeader(COUNT_HEADER)) + { + count = ((Number) requestHeader.getHeader(COUNT_HEADER)).intValue(); + } + else + { + count = Integer.MAX_VALUE; + } + + responseHeader.setHeader(ATTRIBUTES_HEADER, attributes); + + responseHeader.setHeader(STATUS_CODE_HEADER, STATUS_CODE_OK); + List> responseList = new ArrayList>(); + + int rowNo = 0; + for(String type : restriction) + { + ManagedEntityType entityType = _entityTypes.get(type); + if(entityType != null) + { + Map entityMap = _entities.get(entityType); + if(entityMap != null) + { + List entities; + synchronized(entityMap) + { + entities = new ArrayList(entityMap.values()); + } + for(ConfiguredObject entity : entities) + { + if(rowNo++ >= offset) + { + Object[] attrValue = new Object[attributes.size()]; + int col = 0; + for(String attr : attributes) + { + Object value; + if(TYPE_ATTRIBUTE.equals(attr)) + { + value = entityType.getName(); + } + else + { + value = fixValue(entity.getAttribute(attr)); + } + attrValue[col++] = value; + } + responseList.add(Arrays.asList(attrValue)); + } + if(responseList.size()==count) + { + break; + } + } + } + } + + if(responseList.size()==count) + { + break; + } + } + responseHeader.setHeader(COUNT_HEADER, count); + responseMessage = InternalMessage.createListMessage(_virtualHost.getMessageStore(), + responseHeader, + responseList); + return responseMessage; + } + + private Object fixValue(final Object value) + { + Object fixedValue; + if(value instanceof Enum) + { + fixedValue = value.toString(); + } + else if(value instanceof Map) + { + Map oldValue = (Map) value; + Map newValue = new LinkedHashMap(); + for(Map.Entry entry : oldValue.entrySet()) + { + newValue.put(fixValue(entry.getKey()),fixValue(entry.getValue())); + } + fixedValue = newValue; + } + else if(value instanceof Collection) + { + Collection oldValue = (Collection) value; + List newValue = new ArrayList(oldValue.size()); + for(Object o : oldValue) + { + newValue.add(fixValue(o)); + } + fixedValue = newValue; + } + else if(value != null && value.getClass().isArray() && !(value instanceof byte[])) + { + fixedValue = fixValue(Arrays.asList((Object[])value)); + } + else + { + fixedValue = value; + } + return fixedValue; + + } + + + private boolean meetsIndirectRestriction(final ManagedEntityType type, final List restriction) + { + if(restriction.contains(type.getName())) + { + return true; + } + if(type.getParents() != null) + { + for(ManagedEntityType parent : type.getParents()) + { + if(meetsIndirectRestriction(parent, restriction)) + { + return true; + } + } + } + return false; + } + + @Override + public synchronized ManagementNodeConsumer addConsumer(final T target, + final FilterManager filters, + final Class messageClass, + final String consumerName, + final EnumSet options) throws AMQException + { + + final ManagementNodeConsumer managementNodeConsumer = new ManagementNodeConsumer(consumerName,this, target); + target.consumerAdded(managementNodeConsumer); + _consumers.put(consumerName, managementNodeConsumer); + for(ConsumerRegistrationListener listener : _consumerRegistrationListeners) + { + listener.consumerAdded(this, managementNodeConsumer); + } + return managementNodeConsumer; + } + + @Override + public synchronized Collection getConsumers() + { + return new ArrayList(_consumers.values()); + } + + @Override + public void addConsumerRegistrationListener(final ConsumerRegistrationListener listener) + { + _consumerRegistrationListeners.add(listener); + } + + @Override + public void removeConsumerRegistrationListener(final ConsumerRegistrationListener listener) + { + _consumerRegistrationListeners.remove(listener); + } + + @Override + public AuthorizationHolder getAuthorizationHolder() + { + return null; + } + + @Override + public void setAuthorizationHolder(final AuthorizationHolder principalHolder) + { + + } + + @Override + public void setExclusiveOwningSession(final AMQSessionModel owner) + { + + } + + @Override + public AMQSessionModel getExclusiveOwningSession() + { + return null; + } + + @Override + public boolean isExclusive() + { + return false; + } + + @Override + public String getName() + { + return MANAGEMENT_NODE_NAME; + } + + @Override + public UUID getId() + { + return _id; + } + + @Override + public boolean isDurable() + { + return false; + } + + private class ConsumedMessageInstance implements MessageInstance + { + private final ServerMessage _message; + private final InstanceProperties _properties; + + public ConsumedMessageInstance(final ServerMessage message, + final InstanceProperties properties) + { + _message = message; + _properties = properties; + } + + @Override + public int getDeliveryCount() + { + return 0; + } + + @Override + public void incrementDeliveryCount() + { + + } + + @Override + public void decrementDeliveryCount() + { + + } + + @Override + public void addStateChangeListener(final StateChangeListener listener) + { + + } + + @Override + public boolean removeStateChangeListener(final StateChangeListener listener) + { + return false; + } + + + @Override + public boolean acquiredByConsumer() + { + return false; + } + + @Override + public boolean isAcquiredBy(final Consumer consumer) + { + return false; + } + + @Override + public void setRedelivered() + { + + } + + @Override + public boolean isRedelivered() + { + return false; + } + + @Override + public Consumer getDeliveredConsumer() + { + return null; + } + + @Override + public void reject() + { + + } + + @Override + public boolean isRejectedBy(final Consumer consumer) + { + return false; + } + + @Override + public boolean getDeliveredToConsumer() + { + return true; + } + + @Override + public boolean expired() throws AMQException + { + return false; + } + + @Override + public boolean acquire(final Consumer sub) + { + return false; + } + + @Override + public int getMaximumDeliveryCount() + { + return 0; + } + + @Override + public int routeToAlternate(final Action> action, + final ServerTransaction txn) + { + return 0; + } + + + @Override + public Filterable asFilterable() + { + return null; + } + + @Override + public boolean isAvailable() + { + return false; + } + + @Override + public boolean acquire() + { + return false; + } + + @Override + public boolean isAcquired() + { + return false; + } + + @Override + public void release() + { + + } + + @Override + public boolean resend() throws AMQException + { + return false; + } + + @Override + public void delete() + { + + } + + @Override + public boolean isDeleted() + { + return false; + } + + @Override + public ServerMessage getMessage() + { + return _message; + } + + @Override + public InstanceProperties getInstanceProperties() + { + return _properties; + } + + @Override + public TransactionLogResource getOwningResource() + { + return ManagementNode.this; + } + } + + private class ModelObjectListener implements ConfigurationChangeListener + { + @Override + public void stateChanged(final ConfiguredObject object, final State oldState, final State newState) + { + if(newState == State.DELETED) + { + _registry.removeSystemNode(ManagementNode.this); + } + } + + @Override + public void childAdded(final ConfiguredObject object, final ConfiguredObject child) + { + final ManagedEntityType entityType = _entityTypes.get(getManagementClass(child.getClass()).getName()); + if(entityType != null) + { + _entities.get(entityType).put(child.getName(), child); + } + } + + @Override + public void childRemoved(final ConfiguredObject object, final ConfiguredObject child) + { + final ManagedEntityType entityType = _entityTypes.get(getManagementClass(child.getClass()).getName()); + if(entityType != null) + { + _entities.get(entityType).remove(child.getName()); + } + } + + @Override + public void attributeSet(final ConfiguredObject object, + final String attributeName, + final Object oldAttributeValue, + final Object newAttributeValue) + { + + } + } + + private static class MutableMessageHeader implements AMQMessageHeader + { + private final LinkedHashMap _headers = new LinkedHashMap(); + private String _correlationId; + private long _expiration; + private String _userId; + private String _appId; + private String _messageId; + private String _mimeType; + private String _encoding; + private byte _priority; + private long _timestamp; + private String _type; + private String _replyTo; + + public void setCorrelationId(final String correlationId) + { + _correlationId = correlationId; + } + + public void setExpiration(final long expiration) + { + _expiration = expiration; + } + + public void setUserId(final String userId) + { + _userId = userId; + } + + public void setAppId(final String appId) + { + _appId = appId; + } + + public void setMessageId(final String messageId) + { + _messageId = messageId; + } + + public void setMimeType(final String mimeType) + { + _mimeType = mimeType; + } + + public void setEncoding(final String encoding) + { + _encoding = encoding; + } + + public void setPriority(final byte priority) + { + _priority = priority; + } + + public void setTimestamp(final long timestamp) + { + _timestamp = timestamp; + } + + public void setType(final String type) + { + _type = type; + } + + public void setReplyTo(final String replyTo) + { + _replyTo = replyTo; + } + + public String getCorrelationId() + { + return _correlationId; + } + + public long getExpiration() + { + return _expiration; + } + + public String getUserId() + { + return _userId; + } + + public String getAppId() + { + return _appId; + } + + public String getMessageId() + { + return _messageId; + } + + public String getMimeType() + { + return _mimeType; + } + + public String getEncoding() + { + return _encoding; + } + + public byte getPriority() + { + return _priority; + } + + public long getTimestamp() + { + return _timestamp; + } + + public String getType() + { + return _type; + } + + public String getReplyTo() + { + return _replyTo; + } + + @Override + public Object getHeader(final String name) + { + return _headers.get(name); + } + + @Override + public boolean containsHeaders(final Set names) + { + return _headers.keySet().containsAll(names); + } + + @Override + public boolean containsHeader(final String name) + { + return _headers.containsKey(name); + } + + @Override + public Collection getHeaderNames() + { + return Collections.unmodifiableCollection(_headers.keySet()); + } + + public void setHeader(String header, Object value) + { + _headers.put(header,value); + } + + } +} diff --git a/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java new file mode 100644 index 0000000000..98bb20d364 --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.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.management.amqp; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.consumer.ConsumerTarget; +import org.apache.qpid.server.message.internal.InternalMessage; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.util.StateChangeListener; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +class ManagementNodeConsumer implements Consumer +{ + private final long _id = Consumer.SUB_ID_GENERATOR.getAndIncrement(); + private final ManagementNode _managementNode; + private final List _queue = Collections.synchronizedList(new ArrayList()); + private final ConsumerTarget _target; + private final Lock _stateChangeLock = new ReentrantLock(); + private final String _name; + private final StateChangeListener _targetChangeListener = new TargetChangeListener(); + + + public ManagementNodeConsumer(final String consumerName, final ManagementNode managementNode, ConsumerTarget target) + { + _name = consumerName; + _managementNode = managementNode; + _target = target; + target.setStateListener(_targetChangeListener); + } + + @Override + public void externalStateChange() + { + + } + + @Override + public long getBytesOut() + { + return 0; + } + + @Override + public long getMessagesOut() + { + return 0; + } + + @Override + public long getUnacknowledgedBytes() + { + return 0; + } + + @Override + public long getUnacknowledgedMessages() + { + return 0; + } + + @Override + public AMQSessionModel getSessionModel() + { + return _target.getSessionModel(); + } + + @Override + public void setNoLocal(final boolean noLocal) + { + } + + @Override + public long getId() + { + return _id; + } + + @Override + public boolean isSuspended() + { + return false; + } + + @Override + public boolean isClosed() + { + return false; + } + + @Override + public boolean acquires() + { + return true; + } + + @Override + public boolean seesRequeues() + { + return false; + } + + @Override + public void close() throws AMQException + { + + } + + @Override + public boolean trySendLock() + { + return _stateChangeLock.tryLock(); + } + + @Override + public void getSendLock() + { + _stateChangeLock.lock(); + } + + @Override + public void releaseSendLock() + { + _stateChangeLock.unlock(); + } + + + @Override + public boolean isActive() + { + return false; + } + + @Override + public String getName() + { + return _name; + } + + @Override + public void flush() throws AMQException + { + + } + + ManagementNode getManagementNode() + { + return _managementNode; + } + + void send(final InternalMessage response) + { + getSendLock(); + try + { + final ManagementResponse responseEntry = new ManagementResponse(this, response); + if(_queue.isEmpty() && _target.allocateCredit(response)) + { + _target.send(responseEntry,false); + } + else + { + _queue.add(responseEntry); + } + } + catch (AMQException e) + { + e.printStackTrace(); + } + finally + { + releaseSendLock(); + } + } + + private class TargetChangeListener implements StateChangeListener + { + @Override + public void stateChanged(final ConsumerTarget object, + final ConsumerTarget.State oldState, + final ConsumerTarget.State newState) + { + if(newState == ConsumerTarget.State.ACTIVE) + { + deliverMessages(); + } + } + } + + private void deliverMessages() + { + getSendLock(); + try + { + while(!_queue.isEmpty()) + { + + final ManagementResponse managementResponse = _queue.get(0); + if(!_target.isSuspended() && _target.allocateCredit(managementResponse.getMessage())) + { + _queue.remove(0); + _target.send(managementResponse,false); + } + else + { + break; + } + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + finally + { + releaseSendLock(); + } + } +} diff --git a/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeCreator.java b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeCreator.java new file mode 100644 index 0000000000..cdb71f4859 --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeCreator.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.amqp; + +import org.apache.qpid.server.plugin.SystemNodeCreator; + +public class ManagementNodeCreator implements SystemNodeCreator +{ + @Override + public void register(final SystemNodeRegistry registry) + { + ManagementNode managementNode = new ManagementNode(registry,registry.getVirtualHostModel()); + registry.registerSystemNode(managementNode); + } + + @Override + public String getType() + { + return "AMQP-VIRTUALHOST-MANAGEMENT"; + } +} diff --git a/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java new file mode 100644 index 0000000000..e25f327420 --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.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.management.amqp; + +import org.apache.qpid.AMQException; +import org.apache.qpid.server.consumer.Consumer; +import org.apache.qpid.server.filter.Filterable; +import org.apache.qpid.server.message.InstanceProperties; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.internal.InternalMessage; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.util.Action; +import org.apache.qpid.server.util.StateChangeListener; + +class ManagementResponse implements MessageInstance +{ + private final ManagementNodeConsumer _consumer; + private int _deliveryCount; + private boolean _isRedelivered; + private boolean _isDelivered; + private boolean _isDeleted; + private InternalMessage _message; + + ManagementResponse(final ManagementNodeConsumer consumer, final InternalMessage message) + { + _consumer = consumer; + _message = message; + } + + @Override + public int getDeliveryCount() + { + return 0; + } + + @Override + public void incrementDeliveryCount() + { + _deliveryCount++; + } + + @Override + public void decrementDeliveryCount() + { + _deliveryCount--; + } + + @Override + public void addStateChangeListener(final StateChangeListener listener) + { + + } + + @Override + public boolean removeStateChangeListener(final StateChangeListener listener) + { + return false; + } + + + @Override + public boolean acquiredByConsumer() + { + return !isDeleted(); + } + + @Override + public boolean isAcquiredBy(final ManagementNodeConsumer consumer) + { + return consumer == _consumer && !isDeleted(); + } + + @Override + public void setRedelivered() + { + _isRedelivered = true; + } + + @Override + public boolean isRedelivered() + { + return _isRedelivered; + } + + @Override + public ManagementNodeConsumer getDeliveredConsumer() + { + return isDeleted() ? null : _consumer; + } + + @Override + public void reject() + { + delete(); + } + + @Override + public boolean isRejectedBy(final ManagementNodeConsumer consumer) + { + return false; + } + + @Override + public boolean getDeliveredToConsumer() + { + return _isDelivered; + } + + @Override + public boolean expired() throws AMQException + { + return false; + } + + @Override + public boolean acquire(final ManagementNodeConsumer sub) + { + return false; + } + + @Override + public int getMaximumDeliveryCount() + { + return 0; + } + + @Override + public int routeToAlternate(final Action> action, + final ServerTransaction txn) + { + return 0; + } + + + @Override + public Filterable asFilterable() + { + return null; + } + + @Override + public boolean isAvailable() + { + return false; + } + + @Override + public boolean acquire() + { + return false; + } + + @Override + public boolean isAcquired() + { + return !isDeleted(); + } + + @Override + public void release() + { + delete(); + } + + @Override + public boolean resend() throws AMQException + { + return false; + } + + @Override + public void delete() + { + // TODO + } + + @Override + public boolean isDeleted() + { + return _isDeleted; + } + + @Override + public ServerMessage getMessage() + { + return _message; + } + + @Override + public InstanceProperties getInstanceProperties() + { + return InstanceProperties.EMPTY; + } + + @Override + public TransactionLogResource getOwningResource() + { + return _consumer.getManagementNode(); + } +} diff --git a/qpid/java/broker-plugins/management-amqp/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.SystemNodeCreator b/qpid/java/broker-plugins/management-amqp/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.SystemNodeCreator new file mode 100644 index 0000000000..767f93782b --- /dev/null +++ b/qpid/java/broker-plugins/management-amqp/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.SystemNodeCreator @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +org.apache.qpid.server.management.amqp.ManagementNodeCreator diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java index 4d85d52997..0329379713 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java @@ -19,9 +19,6 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html index 9a24e23407..410a5d23ca 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html @@ -35,16 +35,16 @@ Queue Type: - +    - +    - +    - + diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js index 54cfe225c8..606f95e349 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js @@ -277,7 +277,7 @@ define(["dojo/_base/xhr", "exclusive", "owner", "lifetimePolicy", - "type", + "queueType", "typeQualifier", "alertRepeatGap", "alertRepeatGapUnits", @@ -359,14 +359,14 @@ define(["dojo/_base/xhr", bytesDepth = formatter.formatBytes( this.queueData["unacknowledgedBytes"] ); this.unacknowledgedBytes.innerHTML = "(" + bytesDepth.value; this.unacknowledgedBytesUnits.innerHTML = bytesDepth.units + ")"; - this.type.innerHTML = entities.encode(this.queueData[ "type" ]); - if (this.queueData.type == "standard") + this.queueType.innerHTML = entities.encode(this.queueData[ "queueType" ]); + if (this.queueData.queueType == "standard") { this.typeQualifier.style.display = "none"; } else { - this.typeQualifier.innerHTML = entities.encode("(" + queueTypeKeyNames[this.queueData.type] + ": " + this.queueData[queueTypeKeys[this.queueData.type]] + ")"); + this.typeQualifier.innerHTML = entities.encode("(" + queueTypeKeyNames[this.queueData.queueType] + ": " + this.queueData[queueTypeKeys[this.queueData.queueType]] + ")"); } if(this.queueData["messageGroupKey"]) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js index e8b8dd1721..64e821b2dd 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js @@ -96,7 +96,7 @@ define(["dojo/_base/xhr", } } else if (!typeSpecificFields.hasOwnProperty(propName) || - formValues.type === typeSpecificFields[ propName ]) { + formValues.queueType === typeSpecificFields[ propName ]) { if(formValues[ propName ] !== "") { if (fieldConverters.hasOwnProperty(propName)) { @@ -130,7 +130,7 @@ define(["dojo/_base/xhr", theForm = registry.byId("formAddQueue"); array.forEach(theForm.getDescendants(), function(widget) { - if(widget.name === "type") { + if(widget.name === "queueType") { widget.on("change", function(isChecked) { var objId = widget.id + ":fields"; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html index 89b7327957..252deb3100 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html @@ -47,7 +47,7 @@
Type:
- +
diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java index 49cb6aa8cb..d74aa41244 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java @@ -183,7 +183,7 @@ public class QueueMBean extends AMQManagedObject implements ManagedQueue, QueueN @Override public String getQueueType() { - return (String) _queue.getAttribute(Queue.TYPE); + return (String) _queue.getAttribute(Queue.QUEUE_TYPE); } public boolean isDurable() diff --git a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java index 3711a90f3b..f94c206512 100644 --- a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java +++ b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java @@ -127,7 +127,7 @@ public class QueueMBeanTest extends QpidTestCase public void testQueueType() throws Exception { - assertAttribute("queueType", QUEUE_TYPE, Queue.TYPE); + assertAttribute("queueType", QUEUE_TYPE, Queue.QUEUE_TYPE); } public void testMaximumDeliveryCount() throws Exception diff --git a/qpid/java/build.deps b/qpid/java/build.deps index 4dc5b0ca46..0aa35954bf 100644 --- a/qpid/java/build.deps +++ b/qpid/java/build.deps @@ -103,6 +103,7 @@ perftests.test.libs=${test.libs} qpid-test-utils.libs = ${test.libs} ${geronimo-jms} broker-plugins-access-control.test.libs=${test.libs} +broker-plugins-management-amqp.test.libs=${test.libs} broker-plugins-management-http.test.libs=${test.libs} broker-plugins-management-jmx.test.libs=${test.libs} broker-plugins-jdbc-store.test.libs=${test.libs} diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java index b408ad8ad1..b5a4166b55 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableKeyEnumeratorTest.java @@ -64,7 +64,7 @@ public class FieldTableKeyEnumeratorTest extends TestCase } - public void testPropertEnu() + public void testPropertyEnum() { try { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java index 60dac24cfc..fe8c94cee1 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java @@ -30,8 +30,8 @@ import java.io.IOException; public class BasicContentHeaderProperties { //persistent & non-persistent constants, values as per JMS DeliveryMode - public static final int NON_PERSISTENT = 1; - public static final int PERSISTENT = 2; + public static final byte NON_PERSISTENT = 1; + public static final byte PERSISTENT = 2; private static final Logger _logger = LoggerFactory.getLogger(BasicContentHeaderProperties.class); diff --git a/qpid/java/ivy.nexus.xml b/qpid/java/ivy.nexus.xml index 55b2d2d729..8683062288 100644 --- a/qpid/java/ivy.nexus.xml +++ b/qpid/java/ivy.nexus.xml @@ -51,6 +51,12 @@ + + + + + + diff --git a/qpid/java/pom.xml b/qpid/java/pom.xml index 3eb4cfb8c0..3a5c9fd2e8 100644 --- a/qpid/java/pom.xml +++ b/qpid/java/pom.xml @@ -173,6 +173,7 @@ broker-plugins/derby-store broker-plugins/jdbc-provider-bone broker-plugins/jdbc-store + broker-plugins/management-amqp broker-plugins/management-http broker-plugins/management-jmx broker-plugins/memory-store diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/MessageStoreTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/MessageStoreTest.java index f92a133919..de36c6e413 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/MessageStoreTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/MessageStoreTest.java @@ -47,11 +47,10 @@ import org.apache.qpid.server.protocol.v0_8.MessageMetaData; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.UUIDGenerator; import org.apache.qpid.server.plugin.ExchangeType; -import org.apache.qpid.server.queue.AMQPriorityQueue; +import org.apache.qpid.server.queue.PriorityQueue; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.ConflationQueue; -import org.apache.qpid.server.queue.SimpleAMQQueue; +import org.apache.qpid.server.queue.StandardQueue; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.util.BrokerTestHelper; @@ -573,9 +572,9 @@ public class MessageStoreTest extends QpidTestCase if (usePriority) { - assertEquals("Queue is no longer a Priority Queue", AMQPriorityQueue.class, queue.getClass()); + assertEquals("Queue is no longer a Priority Queue", PriorityQueue.class, queue.getClass()); assertEquals("Priority Queue does not have set priorities", - DEFAULT_PRIORTY_LEVEL, ((AMQPriorityQueue) queue).getPriorities()); + DEFAULT_PRIORTY_LEVEL, ((PriorityQueue) queue).getPriorities()); } else if (lastValueQueue) { @@ -584,7 +583,7 @@ public class MessageStoreTest extends QpidTestCase } else { - assertEquals("Queue is not 'simple'", SimpleAMQQueue.class, queue.getClass()); + assertEquals("Queue is not 'simple'", StandardQueue.class, queue.getClass()); } assertEquals("Queue owner is not as expected", queueOwner, queue.getOwner()); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java index 2d6943f643..3c15a45203 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java @@ -26,11 +26,9 @@ import org.apache.qpid.configuration.ClientProperties; 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.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.NotificationCheckTest; import org.apache.qpid.server.queue.QueueArgumentsConverter; -import org.apache.qpid.server.queue.SimpleAMQQueue; -import org.apache.qpid.server.queue.SimpleAMQQueueTest; +import org.apache.qpid.server.queue.StandardQueue; import org.apache.qpid.test.client.destination.AddressBasedDestinationTest; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; @@ -661,7 +659,7 @@ public class QueueManagementTest extends QpidBrokerTestCase final Object messageGroupKey = "test"; final Map arguments = new HashMap(2); arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey); - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP, SimpleAMQQueue.SHARED_MSG_GROUP_ARG_VALUE); + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP, StandardQueue.SHARED_MSG_GROUP_ARG_VALUE); managedBroker.createNewQueue(queueName, null, true, arguments); final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java index 56aec08d09..9028130c18 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java @@ -97,7 +97,7 @@ public class Asserts assertEquals("Unexpected value of queue attribute " + Queue.STATE, State.ACTIVE.name(), queueData.get(Queue.STATE)); assertEquals("Unexpected value of queue attribute " + Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), queueData.get(Queue.LIFETIME_POLICY)); - assertEquals("Unexpected value of queue attribute " + Queue.TYPE, queueType, queueData.get(Queue.TYPE)); + assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_TYPE, queueType, queueData.get(Queue.QUEUE_TYPE)); if (expectedAttributes == null) { assertEquals("Unexpected value of queue attribute " + Queue.EXCLUSIVE, Boolean.FALSE, queueData.get(Queue.EXCLUSIVE)); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java index 969f222316..96ca0c2def 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java @@ -37,7 +37,6 @@ import org.apache.qpid.server.model.Exchange; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.QueueArgumentsConverter; import org.apache.qpid.server.virtualhost.StandardVirtualHostFactory; import org.apache.qpid.test.utils.TestFileUtils; import org.apache.qpid.util.FileUtils; @@ -527,7 +526,7 @@ public class VirtualHostRestTest extends QpidRestTestCase queueData.put(Queue.DURABLE, Boolean.TRUE); if (queueType != null) { - queueData.put(Queue.TYPE, queueType); + queueData.put(Queue.QUEUE_TYPE, queueType); } if (attributes != null) { -- cgit v1.2.1