summaryrefslogtreecommitdiff
path: root/qpid/java/broker/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/broker/src/main')
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java27
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java88
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java26
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java24
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java37
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java15
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java67
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java47
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java23
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java26
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java71
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java33
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java66
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java176
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java20
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java280
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java19
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java86
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java40
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java38
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java68
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java20
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java252
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java77
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java6
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java53
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java38
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java179
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java89
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java291
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java71
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java83
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java30
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java143
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java665
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java19
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java7
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java98
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java145
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java4
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java9
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java47
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java170
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java74
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java28
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java264
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java29
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java40
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java28
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java652
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java66
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java85
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java36
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java59
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java305
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java98
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java314
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java94
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java202
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java67
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java54
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java233
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java516
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java3
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java51
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java90
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java121
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java364
98 files changed, 3574 insertions, 4409 deletions
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index d1ea5dba69..01a0d9900d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
@@ -20,8 +20,8 @@ package org.apache.qpid.server;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import java.util.Map;
import javax.management.JMException;
import javax.management.MBeanException;
@@ -30,6 +30,7 @@ import javax.management.ObjectName;
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.management.common.mbeans.ManagedBroker;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
@@ -60,6 +61,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
private final QueueRegistry _queueRegistry;
private final ExchangeRegistry _exchangeRegistry;
private final ExchangeFactory _exchangeFactory;
+ private final Exchange _defaultExchange;
private final DurableConfigurationStore _durableConfig;
private final VirtualHostImpl.VirtualHostMBean _virtualHostMBean;
@@ -74,6 +76,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
_queueRegistry = virtualHost.getQueueRegistry();
_exchangeRegistry = virtualHost.getExchangeRegistry();
+ _defaultExchange = _exchangeRegistry.getDefaultExchange();
_durableConfig = virtualHost.getDurableConfigurationStore();
_exchangeFactory = virtualHost.getExchangeFactory();
}
@@ -241,7 +244,13 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
*/
public void createNewQueue(String queueName, String owner, boolean durable) throws JMException, MBeanException
{
- AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName));
+ createNewQueue(queueName, owner, durable, null);
+ }
+
+ public void createNewQueue(String queueName, String owner, boolean durable, Map<String,Object> arguments) throws JMException
+ {
+ final AMQShortString queueNameAsAMQShortString = new AMQShortString(queueName);
+ AMQQueue queue = _queueRegistry.getQueue(queueNameAsAMQShortString);
if (queue != null)
{
throw new JMException("The queue \"" + queueName + "\" already exists.");
@@ -256,13 +265,21 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
ownerShortString = new AMQShortString(owner);
}
- queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, getVirtualHost(), null);
+ FieldTable args = null;
+ if(arguments != null)
+ {
+ args = FieldTable.convertToFieldTable(arguments);
+ }
+ final VirtualHost virtualHost = getVirtualHost();
+
+ queue = AMQQueueFactory.createAMQQueueImpl(queueNameAsAMQShortString, durable, ownerShortString,
+ false, false, getVirtualHost(), args);
if (queue.isDurable() && !queue.isAutoDelete())
{
- _durableConfig.createQueue(queue);
+ _durableConfig.createQueue(queue, args);
}
- _queueRegistry.registerQueue(queue);
+ virtualHost.getBindingFactory().addBinding(queueName, queue, _defaultExchange, null);
}
catch (AMQException ex)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 2a96426f02..30d620401f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -22,7 +22,6 @@ package org.apache.qpid.server;
import org.apache.log4j.Logger;
-import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQMethodBody;
@@ -53,6 +52,7 @@ import org.apache.qpid.server.logging.messages.ChannelMessages;
import org.apache.qpid.server.logging.messages.ExchangeMessages;
import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.server.message.MessageMetaData;
import org.apache.qpid.server.message.MessageReference;
import org.apache.qpid.server.message.ServerMessage;
@@ -63,6 +63,7 @@ import org.apache.qpid.server.protocol.AMQSessionModel;
import org.apache.qpid.server.protocol.AMQConnectionModel;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.InboundMessageAdapter;
import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
@@ -693,6 +694,31 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
}
+ public boolean isMaxDeliveryCountEnabled(final long deliveryTag)
+ {
+ final QueueEntry queueEntry = _unacknowledgedMessageMap.get(deliveryTag);
+ if (queueEntry != null)
+ {
+ final int maximumDeliveryCount = queueEntry.getQueue().getMaximumDeliveryCount();
+ return maximumDeliveryCount > 0;
+ }
+
+ return false;
+ }
+
+ public boolean isDeliveredTooManyTimes(final long deliveryTag)
+ {
+ final QueueEntry queueEntry = _unacknowledgedMessageMap.get(deliveryTag);
+ if (queueEntry != null)
+ {
+ final int maximumDeliveryCount = queueEntry.getQueue().getMaximumDeliveryCount();
+ final int numDeliveries = queueEntry.getDeliveryCount();
+ return maximumDeliveryCount != 0 && numDeliveries >= maximumDeliveryCount;
+ }
+
+ return false;
+ }
+
/**
* Called to resend all outstanding unacknowledged messages to this same channel.
*
@@ -740,9 +766,9 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
QueueEntry message = entry.getValue();
long deliveryTag = entry.getKey();
+ //Amend the delivery counter as the client hasn't seen these messages yet.
+ message.decrementDeliveryCount();
-
- ServerMessage msg = message.getMessage();
AMQQueue queue = message.getQueue();
// Our Java Client will always suspend the channel when resending!
@@ -800,6 +826,10 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
QueueEntry message = entry.getValue();
long deliveryTag = entry.getKey();
+
+ //Amend the delivery counter as the client hasn't seen these messages yet.
+ message.decrementDeliveryCount();
+
_unacknowledgedMessageMap.remove(deliveryTag);
message.setRedelivered();
@@ -1060,6 +1090,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(),
deliveryTag,
((SubscriptionImpl)sub).getConsumerTag());
+ entry.incrementDeliveryCount();
}
};
@@ -1248,7 +1279,6 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
private final Collection<QueueEntry> _ackedMessages;
-
public MessageAcknowledgeAction(Collection<QueueEntry> ackedMessages)
{
_ackedMessages = ackedMessages;
@@ -1481,4 +1511,54 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
}
}
}
+
+ public void deadLetter(long deliveryTag) throws AMQException
+ {
+ final UnacknowledgedMessageMap unackedMap = getUnacknowledgedMessageMap();
+ final QueueEntry rejectedQueueEntry = unackedMap.get(deliveryTag);
+
+ if (rejectedQueueEntry == null)
+ {
+ _logger.warn("No message found, unable to DLQ delivery tag: " + deliveryTag);
+ return;
+ }
+ else
+ {
+ final ServerMessage msg = rejectedQueueEntry.getMessage();
+
+ final AMQQueue queue = rejectedQueueEntry.getQueue();
+
+ final Exchange altExchange = queue.getAlternateExchange();
+ unackedMap.remove(deliveryTag);
+
+ if (altExchange == null)
+ {
+ _logger.debug("No alternate exchange configured for queue, must discard the message as unable to DLQ: delivery tag: " + deliveryTag);
+ _actor.message(_logSubject, ChannelMessages.DISCARDMSG_NOALTEXCH(msg.getMessageNumber(), queue.getName(), msg.getRoutingKey()));
+ rejectedQueueEntry.discard();
+ return;
+ }
+
+ final InboundMessage m = new InboundMessageAdapter(rejectedQueueEntry);
+
+ final ArrayList<? extends BaseQueue> destinationQueues = altExchange.route(m);
+
+ if (destinationQueues == null || destinationQueues.isEmpty())
+ {
+ _logger.debug("Routing process provided no queues to enqueue the message on, must discard message as unable to DLQ: delivery tag: " + deliveryTag);
+ _actor.message(_logSubject, ChannelMessages.DISCARDMSG_NOROUTE(msg.getMessageNumber(), altExchange.getName()));
+ rejectedQueueEntry.discard();
+ return;
+ }
+
+ rejectedQueueEntry.routeToAlternate();
+
+ //output operational logging for each delivery post commit
+ for (final BaseQueue destinationQueue : destinationQueues)
+ {
+ _actor.message(_logSubject, ChannelMessages.DEADLETTERMSG(msg.getMessageNumber(), destinationQueue.getNameShortString().asString()));
+ }
+
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
index 400ce50bc4..94ab43c851 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
@@ -170,11 +170,17 @@ public class BindingFactory
{
arguments = Collections.emptyMap();
}
-
- //Perform ACLs
- if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey)))
+
+ // The default exchange bindings must reflect the existence of queues, allow
+ // all operations on it to succeed. It is up to the broker to prevent illegal
+ // attempts at binding to this exchange, not the ACLs.
+ if(exchange != _defaultExchange)
{
- throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ //Perform ACLs
+ if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey)))
+ {
+ throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ }
}
BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments);
@@ -238,10 +244,16 @@ public class BindingFactory
arguments = Collections.emptyMap();
}
- // Check access
- if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue))
+ // The default exchange bindings must reflect the existence of queues, allow
+ // all operations on it to succeed. It is up to the broker to prevent illegal
+ // attempts at binding to this exchange, not the ACLs.
+ if(exchange != _defaultExchange)
{
- throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ // Check access
+ if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue))
+ {
+ throw new AMQSecurityException("Permission denied: unbinding " + bindingKey);
+ }
}
BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments));
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
index 3a28b65a08..759907d4bd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
@@ -62,7 +62,10 @@ public class QueueConfiguration extends ConfigurationPlugin
"capacity",
"flowResumeCapacity",
"lvq",
- "lvqKey"
+ "lvqKey",
+ "sortKey",
+ "maximumDeliveryCount",
+ "deadLetterQueues"
};
}
@@ -167,11 +170,30 @@ public class QueueConfiguration extends ConfigurationPlugin
return getStringValue("lvqKey", null);
}
+
public boolean isTopic()
{
return getBooleanValue("topic");
}
+ public String getQueueSortKey()
+ {
+ return getStringValue("sortKey", null);
+ }
+
+ public int getMaxDeliveryCount()
+ {
+ return getIntValue("maximumDeliveryCount", _vHostConfig.getMaxDeliveryCount());
+ }
+
+ /**
+ * Check if dead letter queue delivery is enabled, deferring to the virtualhost configuration if not set.
+ */
+ public boolean isDeadLetterQueueEnabled()
+ {
+ return getBooleanValue("deadLetterQueues", _vHostConfig.isDeadLetterQueueEnabled());
+ }
+
public static class QueueConfig extends ConfigurationPlugin
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index 0d347873c2..4b42e39aa1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -40,6 +40,8 @@ import org.apache.commons.configuration.SystemConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.exchange.DefaultExchangeFactory;
+import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.signal.SignalHandlerTask;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -805,4 +807,39 @@ public class ServerConfiguration extends ConfigurationPlugin
final List<String> disabledFeatures = getListValue("disabledFeatures", Collections.emptyList());
return disabledFeatures;
}
+
+ public boolean getManagementRightsInferAllAccess()
+ {
+ return getBooleanValue("management.managementRightsInferAllAccess", true);
+ }
+
+ public int getMaxDeliveryCount()
+ {
+ return getConfig().getInt("maximumDeliveryCount", 0);
+ }
+
+ /**
+ * Check if dead letter queue delivery is enabled, defaults to disabled if not set.
+ */
+ public boolean isDeadLetterQueueEnabled()
+ {
+ return getConfig().getBoolean("deadLetterQueues", false);
+ }
+
+ /**
+ * String to affix to end of queue name when generating an alternate exchange for DLQ purposes.
+ */
+ public String getDeadLetterExchangeSuffix()
+ {
+ return getConfig().getString("deadLetterExchangeSuffix", DefaultExchangeFactory.DEFAULT_DLE_NAME_SUFFIX);
+ }
+
+ /**
+ * String to affix to end of queue name when generating a queue for DLQ purposes.
+ */
+ public String getDeadLetterQueueSuffix()
+ {
+ return getConfig().getString("deadLetterQueueSuffix", AMQQueueFactory.DEFAULT_DLQ_NAME_SUFFIX);
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
index 6729a5ce0f..c4e4f701a8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/VirtualHostConfiguration.java
@@ -347,4 +347,18 @@ public class VirtualHostConfiguration extends ConfigurationPlugin
{
return getLongValue("transactionTimeout.idleClose", 0L);
}
+
+ public int getMaxDeliveryCount()
+ {
+ return getIntValue("queues.maximumDeliveryCount", ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount());
+ }
+
+ /**
+ * Check if dead letter queue delivery is enabled, deferring to the broker configuration if not set.
+ */
+ public boolean isDeadLetterQueueEnabled()
+ {
+ return getBooleanValue("queues.deadLetterQueues", ApplicationRegistry.getInstance().getConfiguration().isDeadLetterQueueEnabled());
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java
index 0638ea362f..6f8020fc54 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/plugins/SlowConsumerDetectionQueueConfiguration.java
@@ -87,6 +87,19 @@ public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin
@Override
public void validateConfiguration() throws ConfigurationException
{
+ PluginManager pluginManager;
+ try
+ {
+ pluginManager = ApplicationRegistry.getInstance().getPluginManager();
+ }
+ catch (IllegalStateException ise)
+ {
+ // We see this happen during shutdown due to asynchronous reconfig performed IO threads
+ // running at the same time as the shutdown handler.
+ _policyPlugin = null;
+ return;
+ }
+
if (!containsPositiveLong("messageAge") &&
!containsPositiveLong("depth") &&
!containsPositiveLong("messageCount"))
@@ -96,8 +109,6 @@ public class SlowConsumerDetectionQueueConfiguration extends ConfigurationPlugin
}
SlowConsumerDetectionPolicyConfiguration policyConfig = getConfiguration(SlowConsumerDetectionPolicyConfiguration.class.getName());
-
- PluginManager pluginManager = ApplicationRegistry.getInstance().getPluginManager();
Map<String, SlowConsumerPolicyPluginFactory> factories = pluginManager.getSlowConsumerPlugins();
if (policyConfig == null)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index 7837a9bc38..090c0426cf 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -40,6 +40,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
public class DefaultExchangeFactory implements ExchangeFactory
{
private static final Logger _logger = Logger.getLogger(DefaultExchangeFactory.class);
+ public static final String DEFAULT_DLE_NAME_SUFFIX = "_DLE";
private Map<AMQShortString, ExchangeType<? extends Exchange>> _exchangeClassMap = new HashMap<AMQShortString, ExchangeType<? extends Exchange>>();
private final VirtualHost _host;
@@ -122,7 +123,7 @@ public class DefaultExchangeFactory implements ExchangeFactory
if (exchangeType == null)
{
_logger.error("No such custom exchange class found: \""+String.valueOf(className)+"\"");
- return;
+ continue;
}
Class<? extends ExchangeType> exchangeTypeClass = exchangeType.getClass();
ExchangeType<? extends ExchangeType> type = exchangeTypeClass.newInstance();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
index 0e7459498a..8d2dee5aaa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
@@ -27,7 +27,9 @@ import java.util.concurrent.ConcurrentMap;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -87,12 +89,22 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException
{
- // Check access
- if (!_host.getSecurityManager().authoriseDelete(_exchangeMap.get(name)))
+ final Exchange exchange = _exchangeMap.get(name);
+ if (exchange == null)
+ {
+ throw new AMQException(AMQConstant.NOT_FOUND, "Unknown exchange " + name, null);
+ }
+
+ if (ExchangeDefaults.DEFAULT_EXCHANGE_NAME.equals(name))
+ {
+ throw new AMQException(AMQConstant.NOT_ALLOWED, "Cannot unregister the default exchange", null);
+ }
+
+ if (!_host.getSecurityManager().authoriseDelete(exchange))
{
throw new AMQSecurityException();
}
-
+
// TODO: check inUse argument
Exchange e = _exchangeMap.remove(name);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
index bd75f7bc51..76f86ea1b4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java
@@ -117,7 +117,7 @@ public class FanoutExchange extends AbstractExchange
public boolean isBound(AMQShortString routingKey, AMQQueue queue)
{
- return _queues.contains(queue);
+ return _queues.containsKey(queue);
}
public boolean isBound(AMQShortString routingKey)
@@ -129,7 +129,7 @@ public class FanoutExchange extends AbstractExchange
public boolean isBound(AMQQueue queue)
{
- return _queues.contains(queue);
+ return _queues.containsKey(queue);
}
public boolean hasBindings()
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java
index 66c9b5b552..caed8f4b94 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java
@@ -20,12 +20,21 @@
*/
package org.apache.qpid.server.exchange;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.server.binding.Binding;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.virtualhost.VirtualHost;
import javax.management.JMException;
+import javax.management.MBeanException;
import javax.management.openmbean.*;
+
+import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
@@ -94,5 +103,48 @@ final class HeadersExchangeMBean extends AbstractExchangeMBean<HeadersExchange>
return bindingList;
}
+ @Override
+ public void createNewBinding(String queueName, String binding) throws JMException
+ {
+ VirtualHost vhost = getExchange().getVirtualHost();
+ AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName));
+ if (queue == null)
+ {
+ throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost.");
+ }
+
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+
+ final Map<String,Object> arguments = new HashMap<String, Object>();
+ final String[] bindings = binding.split(",");
+ for (int i = 0; i < bindings.length; i++)
+ {
+ final String[] keyAndValue = bindings[i].split("=");
+ if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2 || keyAndValue[0].length() == 0)
+ {
+ throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" ");
+ }
+
+ if(keyAndValue.length == 1)
+ {
+ //no value was given, only a key. Use an empty value to signal match on key presence alone
+ arguments.put(keyAndValue[0], "");
+ }
+ else
+ {
+ arguments.put(keyAndValue[0], keyAndValue[1]);
+ }
+ }
+ try
+ {
+ vhost.getBindingFactory().addBinding(binding,queue,getExchange(),arguments);
+ }
+ catch (AMQException ex)
+ {
+ JMException jme = new JMException(ex.toString());
+ throw new MBeanException(jme, "Error creating new binding " + binding);
+ }
+ CurrentActor.remove();
+ }
} // End of MBean class
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
index c5f2d1e808..5a5ef5e6c5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
import java.util.concurrent.atomic.AtomicLong;
@@ -59,9 +58,8 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager
return _bytesCredit.get() > 0L;
}
- public boolean useCreditForMessage(ServerMessage msg)
+ public boolean useCreditForMessage(long msgSize)
{
- final long msgSize = msg.getSize();
if(hasCredit())
{
if(_bytesCredit.addAndGet(-msgSize) >= 0)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
index b47f986155..c6771177ac 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
public class CreditCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10
{
@@ -118,7 +117,7 @@ public class CreditCreditManager extends AbstractFlowCreditManager implements Fl
return (_bytesCredit != 0L && _messageCredit != 0L);
}
- public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ public synchronized boolean useCreditForMessage(long msgSize)
{
if(_messageCredit >= 0L)
{
@@ -130,10 +129,10 @@ public class CreditCreditManager extends AbstractFlowCreditManager implements Fl
return true;
}
- else if(msg.getSize() <= _bytesCredit)
+ else if(msgSize <= _bytesCredit)
{
_messageCredit--;
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
@@ -151,9 +150,9 @@ public class CreditCreditManager extends AbstractFlowCreditManager implements Fl
}
else if(_bytesCredit >= 0L)
{
- if(msg.getSize() <= _bytesCredit)
+ if(msgSize <= _bytesCredit)
{
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
index bec51d361d..8a80262983 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -41,6 +40,6 @@ public interface FlowCreditManager
public boolean hasCredit();
- public boolean useCreditForMessage(ServerMessage msg);
+ public boolean useCreditForMessage(long msgSize);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
index 901b71fd1f..6fcc687440 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -47,7 +46,7 @@ public class LimitlessCreditManager extends AbstractFlowCreditManager implements
return true;
}
- public boolean useCreditForMessage(ServerMessage msg)
+ public boolean useCreditForMessage(long msgSize)
{
return true;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
index 19a9ac1d23..0e6ce70a60 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
/*
*
@@ -62,7 +61,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
return (_messageCredit > 0L) && ( _bytesCredit > 0L );
}
- public synchronized boolean useCreditForMessage(ServerMessage msg)
+ public synchronized boolean useCreditForMessage(final long msgSize)
{
if(_messageCredit == 0L)
{
@@ -71,7 +70,6 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl
}
else
{
- final long msgSize = msg.getSize();
if(msgSize > _bytesCredit)
{
setSuspended(true);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
index a386f66b11..9b7c40e923 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java
@@ -1,6 +1,5 @@
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
import java.util.concurrent.atomic.AtomicLong;
@@ -61,7 +60,7 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen
return _messageCredit.get() > 0L;
}
- public boolean useCreditForMessage(ServerMessage msg)
+ public boolean useCreditForMessage(long msgSize)
{
if(hasCredit())
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
index 026804439c..a193f8fae4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager
{
@@ -133,7 +132,7 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
&& (_messageCreditLimit == 0L || _messageCredit > 0);
}
- public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ public synchronized boolean useCreditForMessage(final long msgSize)
{
if(_messageCreditLimit != 0L)
{
@@ -147,10 +146,10 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
}
else
{
- if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit))
+ if((_bytesCredit >= msgSize) || (_bytesCredit == _bytesCreditLimit))
{
_messageCredit--;
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
@@ -176,9 +175,9 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F
}
else
{
- if((_bytesCredit >= msg.getSize()) || (_bytesCredit == _bytesCreditLimit))
+ if((_bytesCredit >= msgSize) || (_bytesCredit == _bytesCreditLimit))
{
- _bytesCredit -= msg.getSize();
+ _bytesCredit -= msgSize;
return true;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
index 10f578551a..a0c2e9f977 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java
@@ -20,10 +20,12 @@
*/
package org.apache.qpid.server.flow;
-import org.apache.qpid.server.message.ServerMessage;
+import org.apache.log4j.Logger;
public class WindowCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10
{
+ private static final Logger LOGGER = Logger.getLogger(WindowCreditManager.class);
+
private volatile long _bytesCreditLimit;
private volatile long _messageCreditLimit;
@@ -43,6 +45,15 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
+ public long getBytesCreditLimit()
+ {
+ return _bytesCreditLimit;
+ }
+
+ public long getMessageCreditLimit()
+ {
+ return _messageCreditLimit;
+ }
public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit)
{
@@ -70,31 +81,30 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
public synchronized void restoreCredit(final long messageCredit, final long bytesCredit)
{
+ _messageUsed -= messageCredit;
+ if(_messageUsed < 0L)
+ {
+ LOGGER.error("Message credit used value was negative: "+ _messageUsed);
+ _messageUsed = 0;
+ }
+
boolean notifyIncrease = true;
+
if(_messageCreditLimit > 0L)
{
notifyIncrease = (_messageUsed != _messageCreditLimit);
- _messageUsed -= messageCredit;
-
- //TODO log warning
- if(_messageUsed < 0L)
- {
- _messageUsed = 0;
- }
}
-
+ _bytesUsed -= bytesCredit;
+ if(_bytesUsed < 0L)
+ {
+ LOGGER.error("Bytes credit used value was negative: "+ _messageUsed);
+ _bytesUsed = 0;
+ }
if(_bytesCreditLimit > 0L)
{
notifyIncrease = notifyIncrease && bytesCredit>0;
- _bytesUsed -= bytesCredit;
-
- //TODO log warning
- if(_bytesUsed < 0L)
- {
- _bytesUsed = 0;
- }
if(notifyIncrease)
{
@@ -102,10 +112,7 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
}
-
-
setSuspended(!hasCredit());
-
}
@@ -116,7 +123,7 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
&& (_messageCreditLimit < 0L || _messageCreditLimit > _messageUsed);
}
- public synchronized boolean useCreditForMessage(final ServerMessage msg)
+ public synchronized boolean useCreditForMessage(final long msgSize)
{
if(_messageCreditLimit >= 0L)
{
@@ -128,10 +135,10 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
return true;
}
- else if(_bytesUsed + msg.getSize() <= _bytesCreditLimit)
+ else if(_bytesUsed + msgSize <= _bytesCreditLimit)
{
_messageUsed++;
- _bytesUsed += msg.getSize();
+ _bytesUsed += msgSize;
return true;
}
@@ -149,9 +156,9 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
else if(_bytesCreditLimit >= 0L)
{
- if(_bytesUsed + msg.getSize() <= _bytesCreditLimit)
+ if(_bytesUsed + msgSize <= _bytesCreditLimit)
{
- _bytesUsed += msg.getSize();
+ _bytesUsed += msgSize;
return true;
}
@@ -169,18 +176,6 @@ public class WindowCreditManager extends AbstractFlowCreditManager implements Fl
}
- public void stop()
- {
- if(_bytesCreditLimit > 0)
- {
- _bytesCreditLimit = 0;
- }
- if(_messageCreditLimit > 0)
- {
- _messageCreditLimit = 0;
- }
-
- }
public synchronized void addCredit(long count, long bytes)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
index 14ce85530e..bbb009003c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
@@ -127,16 +127,15 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB
final ClientDeliveryMethod getDeliveryMethod = new ClientDeliveryMethod()
{
- int _msg;
-
public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
throws AMQException
{
- singleMessageCredit.useCreditForMessage(entry.getMessage());
+ singleMessageCredit.useCreditForMessage(entry.getMessage().getSize());
if(entry.getMessage() instanceof AMQMessage)
{
session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(),
deliveryTag, queue.getMessageCount());
+ entry.incrementDeliveryCount();
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
index 62dd76f832..0ea88e4ab6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java
@@ -59,7 +59,6 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
_logger.debug("Rejecting:" + body.getDeliveryTag() +
": Requeue:" + body.getRequeue() +
- //": Resend:" + evt.getMethod().resend +
" on channel:" + channel.debugIdentity());
}
@@ -70,26 +69,23 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
if (message == null)
{
_logger.warn("Dropping reject request as message is null for tag:" + deliveryTag);
-// throw evt.getMethod().getChannelException(AMQConstant.NOT_FOUND, "Delivery Tag(" + deliveryTag + ")not known");
}
else
{
if (message.isQueueDeleted())
{
- _logger.warn("Message's Queue as already been purged, unable to Reject. " +
- "Dropping message should use Dead Letter Queue");
+ _logger.warn("Message's Queue has already been purged, dropping message");
message = channel.getUnacknowledgedMessageMap().remove(deliveryTag);
if(message != null)
{
message.discard();
}
- //sendtoDeadLetterQueue(msg)
return;
}
if (message.getMessage() == null)
{
- _logger.warn("Message as already been purged, unable to Reject.");
+ _logger.warn("Message has already been purged, unable to Reject.");
return;
}
@@ -98,27 +94,44 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR
{
_logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage() +
": Requeue:" + body.getRequeue() +
- //": Resend:" + evt.getMethod().resend +
" on channel:" + channel.debugIdentity());
}
- // If we haven't requested message to be resent to this consumer then reject it from ever getting it.
- //if (!evt.getMethod().resend)
- {
- message.reject();
- }
+ message.reject();
if (body.getRequeue())
{
channel.requeue(deliveryTag);
+
+ //this requeue represents a message rejected from the pre-dispatch queue
+ //therefore we need to amend the delivery counter.
+ message.decrementDeliveryCount();
}
else
{
- _logger.warn("Dropping message as requeue not required and there is no dead letter queue");
- message = channel.getUnacknowledgedMessageMap().remove(deliveryTag);
- //sendtoDeadLetterQueue(AMQMessage message)
-// message.queue = channel.getDefaultDeadLetterQueue();
-// channel.requeue(deliveryTag);
+ final boolean maxDeliveryCountEnabled = channel.isMaxDeliveryCountEnabled(deliveryTag);
+ _logger.debug("maxDeliveryCountEnabled: " + maxDeliveryCountEnabled + " deliveryTag " + deliveryTag);
+ if (maxDeliveryCountEnabled)
+ {
+ final boolean deliveredTooManyTimes = channel.isDeliveredTooManyTimes(deliveryTag);
+ _logger.debug("deliveredTooManyTimes: " + deliveredTooManyTimes + " deliveryTag " + deliveryTag);
+ if (deliveredTooManyTimes)
+ {
+ channel.deadLetter(body.getDeliveryTag());
+ }
+ else
+ {
+ //this requeue represents a message rejected because of a recover/rollback that we
+ //are not ready to DLQ. We rely on the reject command to resend from the unacked map
+ //and therefore need to increment the delivery counter so we cancel out the effect
+ //of the AMQChannel#resend() decrement.
+ message.incrementDeliveryCount();
+ }
+ }
+ else
+ {
+ channel.deadLetter(body.getDeliveryTag());
+ }
}
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
index 8391a4b184..f2119f7faa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
@@ -25,8 +25,10 @@ import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQMethodBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.framing.QueueUnbindBody;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.exchange.Exchange;
@@ -62,7 +64,7 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
final AMQQueue queue;
- final AMQShortString routingKey;
+ final AMQShortString routingKey;
if (body.getQueue() == null)
{
@@ -114,10 +116,21 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
_log.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey);
}
- MethodRegistry_0_9 methodRegistry = (MethodRegistry_0_9) session.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createQueueUnbindOkBody();
+ final MethodRegistry registry = session.getMethodRegistry();
+ final AMQMethodBody responseBody;
+ if (registry instanceof MethodRegistry_0_9)
+ {
+ responseBody = ((MethodRegistry_0_9)registry).createQueueUnbindOkBody();
+ }
+ else if (registry instanceof MethodRegistry_0_91)
+ {
+ responseBody = ((MethodRegistry_0_91)registry).createQueueUnbindOkBody();
+ }
+ else
+ {
+ // 0-8 does not support QueueUnbind
+ throw new AMQException(AMQConstant.COMMAND_INVALID, "QueueUnbind not present in AMQP version: " + session.getProtocolVersion(), null);
+ }
session.writeFrame(responseBody.generateFrame(channelId));
-
-
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
index 4643dee0a3..20ba3af458 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java
@@ -72,7 +72,12 @@ public class TxRollbackHandler implements StateAwareMethodListener<TxRollbackBod
};
channel.rollback(task);
-
+
+ //Now resend all the unacknowledged messages back to the original subscribers.
+ //(Must be done after the TxnRollback-ok response).
+ // Why, are we not allowed to send messages back to client before the ok method?
+ channel.resend(false);
+
}
catch (AMQException e)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
index ed8c0d0ce9..b5df212904 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/Channel_logmessages.properties
@@ -32,3 +32,7 @@ FLOW_REMOVED = CHN-1006 : Flow Control Removed
# 0 - time in milliseconds
OPEN_TXN = CHN-1007 : Open Transaction : {0,number} ms
IDLE_TXN = CHN-1008 : Idle Transaction : {0,number} ms
+
+DISCARDMSG_NOALTEXCH = CHN-1009 : Discarded message : {0,number} as no alternate exchange configured for queue : {1} routing key : {2}
+DISCARDMSG_NOROUTE = CHN-1010 : Discarded message : {0,number} as no binding on alternate exchange : {1}
+DEADLETTERMSG = CHN-1011 : Message : {0,number} moved to dead letter queue : {1}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
index c4ffcd26bf..6c9d6e39de 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java
@@ -52,8 +52,6 @@ public abstract class AMQManagedObject extends DefaultManagedObject
*/
protected long _notificationSequenceNumber = 0;
- protected MBeanInfo _mbeanInfo;
-
protected LogActor _logActor;
protected AMQManagedObject(Class<?> managementInterface, String typeName)
@@ -63,27 +61,8 @@ public abstract class AMQManagedObject extends DefaultManagedObject
// CurrentActor will be defined as these objects are created during
// broker startup.
_logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger());
- buildMBeanInfo();
- }
-
- @Override
- public MBeanInfo getMBeanInfo()
- {
- return _mbeanInfo;
- }
-
- private void buildMBeanInfo() throws NotCompliantMBeanException
- {
- _mbeanInfo = new MBeanInfo(this.getClass().getName(),
- MBeanIntrospector.getMBeanDescription(this.getClass()),
- MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()),
- MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()),
- MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()),
- this.getNotificationInfo());
}
-
-
// notification broadcaster implementation
public void addNotificationListener(NotificationListener listener,
@@ -99,8 +78,5 @@ public abstract class AMQManagedObject extends DefaultManagedObject
_broadcaster.removeNotificationListener(listener);
}
- public MBeanNotificationInfo[] getNotificationInfo()
- {
- return null;
- }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java
new file mode 100644
index 0000000000..68350a1632
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java
@@ -0,0 +1,71 @@
+package org.apache.qpid.server.management;
+
+import javax.management.Notification;
+
+import javax.management.JMException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.monitor.MonitorNotification;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularType;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+
+public abstract class AbstractAMQManagedConnectionObject extends AMQManagedObject implements ManagedConnection
+{
+ protected final String _name;
+
+ protected static final OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN };
+ protected static final CompositeType _channelType;
+ protected static final TabularType _channelsType;
+
+ protected static final String BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION_STR =
+ "Broker Management Console has closed the connection.";
+
+ static
+ {
+ try
+ {
+ _channelType = new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]),
+ COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), _channelAttributeTypes);
+ _channelsType = new TabularType("Channels", "Channels", _channelType, (String[]) TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()]));
+ }
+ catch (JMException ex)
+ {
+ // This is not expected to ever occur.
+ throw new RuntimeException("Got JMException in static initializer.", ex);
+ }
+ }
+
+ protected AbstractAMQManagedConnectionObject(final String remoteAddress) throws NotCompliantMBeanException
+ {
+ super(ManagedConnection.class, ManagedConnection.TYPE);
+ _name = "anonymous".equals(remoteAddress) ? (remoteAddress + hashCode()) : remoteAddress;
+ }
+
+ @Override
+ public String getObjectInstanceName()
+ {
+ return ObjectName.quote(_name);
+ }
+
+ public void notifyClients(String notificationMsg)
+ {
+ final Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber,
+ System.currentTimeMillis(), notificationMsg);
+ _broadcaster.sendNotification(n);
+ }
+
+ @Override
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED };
+ String name = MonitorNotification.class.getName();
+ String description = "Channel count has reached threshold value";
+ MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description);
+
+ return new MBeanNotificationInfo[] { info1 };
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
index e44b8c41cb..0c3a5fc571 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java
@@ -21,6 +21,8 @@
package org.apache.qpid.server.management;
import javax.management.JMException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
@@ -28,7 +30,6 @@ import javax.management.StandardMBean;
import org.apache.log4j.Logger;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
/**
* Provides implementation of the boilerplate ManagedObject interface. Most managed objects should find it useful
@@ -37,11 +38,13 @@ import org.apache.qpid.server.registry.IApplicationRegistry;
*/
public abstract class DefaultManagedObject extends StandardMBean implements ManagedObject
{
- private static final Logger LOGGER = Logger.getLogger(ApplicationRegistry.class);
+ private static final Logger LOGGER = Logger.getLogger(DefaultManagedObject.class);
- private Class<?> _managementInterface;
+ private final Class<?> _managementInterface;
- private String _typeName;
+ private final String _typeName;
+
+ private final MBeanInfo _mbeanInfo;
private ManagedObjectRegistry _registry;
@@ -51,6 +54,13 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
super(managementInterface);
_managementInterface = managementInterface;
_typeName = typeName;
+ _mbeanInfo = buildMBeanInfo();
+ }
+
+ @Override
+ public MBeanInfo getMBeanInfo()
+ {
+ return _mbeanInfo;
}
public String getType()
@@ -98,7 +108,6 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
return getObjectInstanceName() + "[" + getType() + "]";
}
-
/**
* Created the ObjectName as per the JMX Specs
* @return ObjectName
@@ -161,4 +170,18 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana
return "";
}
+ private MBeanInfo buildMBeanInfo() throws NotCompliantMBeanException
+ {
+ return new MBeanInfo(this.getClass().getName(),
+ MBeanIntrospector.getMBeanDescription(this.getClass()),
+ MBeanIntrospector.getMBeanAttributesInfo(getManagementInterface()),
+ MBeanIntrospector.getMBeanConstructorsInfo(this.getClass()),
+ MBeanIntrospector.getMBeanOperationsInfo(getManagementInterface()),
+ this.getNotificationInfo());
+ }
+
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ return null;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
index b44964f176..8583e8d57b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java
@@ -38,10 +38,13 @@ import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
+import javax.management.Notification;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
@@ -49,11 +52,13 @@ import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.MBeanServerForwarder;
+import javax.management.remote.rmi.RMIConnection;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.management.remote.rmi.RMIJRMPServerImpl;
import javax.management.remote.rmi.RMIServerImpl;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
+import javax.security.auth.Subject;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
@@ -63,6 +68,7 @@ import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
/**
* This class starts up an MBeanserver. If out of the box agent has been enabled then there are no
@@ -223,7 +229,40 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
* The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer
* on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's.
*/
- final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(_jmxPortConnectorServer, csf, ssf, env);
+ final Map<String, String> connectionIdUsernameMap = new ConcurrentHashMap<String, String>();
+ final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(_jmxPortConnectorServer, csf, ssf, env)
+ {
+
+ /**
+ * Override makeClient so we can cache the username of the client in a Map keyed by connectionId.
+ * ConnectionId is guaranteed to be unique per client connection, according to the JMS spec.
+ * An instance of NotificationListener (mapCleanupListener) will be responsible for removing these Map
+ * entries.
+ *
+ * @see javax.management.remote.rmi.RMIJRMPServerImpl#makeClient(java.lang.String, javax.security.auth.Subject)
+ */
+ @Override
+ protected RMIConnection makeClient(String connectionId, Subject subject) throws IOException
+ {
+ final RMIConnection makeClient = super.makeClient(connectionId, subject);
+ final UsernamePrincipal usernamePrincipalFromSubject = UsernamePrincipal.getUsernamePrincipalFromSubject(subject);
+ connectionIdUsernameMap.put(connectionId, usernamePrincipalFromSubject.getName());
+ return makeClient;
+ }
+ };
+
+ // Create a Listener responsible for removing the map entries add by the #makeClient entry above.
+ final NotificationListener mapCleanupListener = new NotificationListener()
+ {
+
+ @Override
+ public void handleNotification(Notification notification, Object handback)
+ {
+ final String connectionId = ((JMXConnectionNotification) notification).getConnectionId();
+ connectionIdUsernameMap.remove(connectionId);
+ }
+ };
+
String localHost;
try
{
@@ -295,13 +334,26 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance();
_cs.setMBeanServerForwarder(mbsf);
- NotificationFilterSupport filter = new NotificationFilterSupport();
- filter.enableType(JMXConnectionNotification.OPENED);
- filter.enableType(JMXConnectionNotification.CLOSED);
- filter.enableType(JMXConnectionNotification.FAILED);
+
// Get the handler that is used by the above MBInvocationHandler Proxy.
- // which is the MBeanInvocationHandlerImpl and so also a NotificationListener
- _cs.addNotificationListener((NotificationListener) Proxy.getInvocationHandler(mbsf), filter, null);
+ // which is the MBeanInvocationHandlerImpl and so also a NotificationListener.
+ final NotificationListener invocationHandler = (NotificationListener) Proxy.getInvocationHandler(mbsf);
+
+ // Install a notification listener on OPENED, CLOSED, and FAILED,
+ // passing the map of connection-ids to usernames as hand-back data.
+ final NotificationFilterSupport invocationHandlerFilter = new NotificationFilterSupport();
+ invocationHandlerFilter.enableType(JMXConnectionNotification.OPENED);
+ invocationHandlerFilter.enableType(JMXConnectionNotification.CLOSED);
+ invocationHandlerFilter.enableType(JMXConnectionNotification.FAILED);
+ _cs.addNotificationListener(invocationHandler, invocationHandlerFilter, connectionIdUsernameMap);
+
+ // Install a second notification listener on CLOSED AND FAILED only to remove the entry from the
+ // Map. Here we rely on the fact that JMX will call the listeners in the order in which they are
+ // installed.
+ final NotificationFilterSupport mapCleanupHandlerFilter = new NotificationFilterSupport();
+ mapCleanupHandlerFilter.enableType(JMXConnectionNotification.CLOSED);
+ mapCleanupHandlerFilter.enableType(JMXConnectionNotification.FAILED);
+ _cs.addNotificationListener(mapCleanupListener, mapCleanupHandlerFilter, null);
_cs.start();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
index 169195304c..40a221e0ba 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
@@ -26,6 +26,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessControlContext;
import java.security.AccessController;
+import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
@@ -45,6 +46,7 @@ import org.apache.log4j.Logger;
import org.apache.qpid.server.logging.actors.ManagementActor;
import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.access.Operation;
@@ -56,22 +58,54 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
{
private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class);
+ private final IApplicationRegistry _appRegistry = ApplicationRegistry.getInstance();
private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate";
private MBeanServer _mbs;
- private static ManagementActor _logActor;
-
+ private final ManagementActor _logActor = new ManagementActor(_appRegistry.getRootMessageLogger());
+ private final boolean _managementRightsInferAllAccess =
+ _appRegistry.getConfiguration().getManagementRightsInferAllAccess();
+
public static MBeanServerForwarder newProxyInstance()
{
final InvocationHandler handler = new MBeanInvocationHandlerImpl();
final Class<?>[] interfaces = new Class[] { MBeanServerForwarder.class };
-
- _logActor = new ManagementActor(ApplicationRegistry.getInstance().getRootMessageLogger());
-
Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler);
return MBeanServerForwarder.class.cast(proxy);
}
+ private boolean invokeDirectly(String methodName, Object[] args, Subject subject)
+ {
+ // Allow operations performed locally on behalf of the connector server itself
+ if (subject == null)
+ {
+ return true;
+ }
+
+ if (args == null || DELEGATE.equals(args[0]))
+ {
+ return true;
+ }
+
+ // Allow querying available object names
+ if (methodName.equals("queryNames"))
+ {
+ return true;
+ }
+
+ if (args[0] instanceof ObjectName)
+ {
+ ObjectName mbean = (ObjectName) args[0];
+
+ if(!DefaultManagedObject.DOMAIN.equalsIgnoreCase(mbean.getDomain()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
final String methodName = getMethodName(method, args);
@@ -95,36 +129,24 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
return null;
}
+ // Restrict access to "createMBean" and "unregisterMBean" to any user
+ if (methodName.equals("createMBean") || methodName.equals("unregisterMBean"))
+ {
+ _logger.debug("User trying to create or unregister an MBean");
+ throw new SecurityException("Access denied: " + methodName);
+ }
+
// Retrieve Subject from current AccessControlContext
AccessControlContext acc = AccessController.getContext();
Subject subject = Subject.getSubject(acc);
try
{
- // Allow operations performed locally on behalf of the connector server itself
- if (subject == null)
+ if(invokeDirectly(methodName, args, subject))
{
return method.invoke(_mbs, args);
}
-
- if (args == null || DELEGATE.equals(args[0]))
- {
- return method.invoke(_mbs, args);
- }
-
- // Restrict access to "createMBean" and "unregisterMBean" to any user
- if (methodName.equals("createMBean") || methodName.equals("unregisterMBean"))
- {
- _logger.debug("User trying to create or unregister an MBean");
- throw new SecurityException("Access denied: " + methodName);
- }
-
- // Allow querying available object names
- if (methodName.equals("queryNames"))
- {
- return method.invoke(_mbs, args);
- }
-
+
// Retrieve JMXPrincipal from Subject
Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
if (principals == null || principals.isEmpty())
@@ -134,23 +156,23 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
// Save the subject
SecurityManager.setThreadSubject(subject);
-
+
// Get the component, type and impact, which may be null
String type = getType(method, args);
String vhost = getVirtualHost(method, args);
int impact = getImpact(method, args);
-
+
// Get the security manager for the virtual host (if set)
SecurityManager security;
if (vhost == null)
{
- security = ApplicationRegistry.getInstance().getSecurityManager();
+ security = _appRegistry.getSecurityManager();
}
else
{
- security = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
+ security = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
}
-
+
if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO)
{
// Check for read-only method invocation permission
@@ -159,25 +181,33 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
throw new SecurityException("Permission denied: Access " + methodName);
}
}
- else if (isUpdateMethod(methodName))
- {
- // Check for setting properties permission
- if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
- {
- throw new SecurityException("Permission denied: Update " + methodName);
- }
- }
- else
- {
- // Check for invoking/executing method action/operation permission
- if (!security.authoriseMethod(Operation.EXECUTE, type, methodName))
- {
- throw new SecurityException("Permission denied: Execute " + methodName);
- }
- }
-
- // Actually invoke the method
- return method.invoke(_mbs, args);
+ else
+ {
+ // Check for setting properties permission
+ if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
+ {
+ throw new SecurityException("Permission denied: Update " + methodName);
+ }
+ }
+
+ boolean oldAccessChecksDisabled = false;
+ if(_managementRightsInferAllAccess)
+ {
+ oldAccessChecksDisabled = SecurityManager.setAccessChecksDisabled(true);
+ }
+
+ try
+ {
+ // Actually invoke the method
+ return method.invoke(_mbs, args);
+ }
+ finally
+ {
+ if(_managementRightsInferAllAccess)
+ {
+ SecurityManager.setAccessChecksDisabled(oldAccessChecksDisabled);
+ }
+ }
}
catch (InvocationTargetException e)
{
@@ -290,28 +320,44 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is"));
}
-
- private boolean isUpdateMethod(String methodName)
- {
- //handle standard set methods from MBeanServer
- return methodName.startsWith("set");
- }
-
- public void handleNotification(Notification notification, Object handback)
+ /**
+ * Receives notifications from the MBeanServer.
+ */
+ public void handleNotification(final Notification notification, final Object handback)
{
assert notification instanceof JMXConnectionNotification;
- // only RMI Connections are serviced here, Local API atta
- // rmi://169.24.29.116 guest 3
- String[] connectionData = ((JMXConnectionNotification) notification).getConnectionId().split(" ");
- String user = connectionData[1];
+ final String connectionId = ((JMXConnectionNotification) notification).getConnectionId();
+ final String type = notification.getType();
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Notification connectionId : " + connectionId + " type : " + type
+ + " Notification handback : " + handback);
+ }
+
+ // Normally JMXManagedObjectRegistry provides a Map as handback data containing a map
+ // between connection id and username.
+ String user = null;
+ if (handback != null && handback instanceof Map)
+ {
+ final Map<String, String> connectionIdUsernameMap = (Map<String, String>) handback;
+ user = connectionIdUsernameMap.get(connectionId);
+ }
+
+ // If user is still null, fallback to an unordered list of Principals from the connection id.
+ if (user == null)
+ {
+ final String[] splitConnectionId = connectionId.split(" ");
+ user = splitConnectionId[1];
+ }
- if (notification.getType().equals(JMXConnectionNotification.OPENED))
+ if (JMXConnectionNotification.OPENED.equals(type))
{
_logActor.message(ManagementConsoleMessages.OPEN(user));
}
- else if (notification.getType().equals(JMXConnectionNotification.CLOSED) ||
- notification.getType().equals(JMXConnectionNotification.FAILED))
+ else if (JMXConnectionNotification.CLOSED.equals(type) ||
+ JMXConnectionNotification.FAILED.equals(type))
{
_logActor.message(ManagementConsoleMessages.CLOSE(user));
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
index 0e0b18aa2f..4fcbaa237e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.message;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.AMQChannel;
@@ -65,7 +66,6 @@ public class AMQMessage extends AbstractServerMessageImpl
WeakReference<AMQChannel> _channelRef;
-
public AMQMessage(StoredMessage<MessageMetaData> handle)
{
this(handle, null);
@@ -122,7 +122,15 @@ public class AMQMessage extends AbstractServerMessageImpl
public String getRoutingKey()
{
- // TODO
+ MessageMetaData messageMetaData = getMessageMetaData();
+ if (messageMetaData != null)
+ {
+ AMQShortString routingKey = messageMetaData.getMessagePublishInfo().getRoutingKey();
+ if (routingKey != null)
+ {
+ return routingKey.asString();
+ }
+ }
return null;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
index 186bb8601c..80c28332c0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.message;
import java.util.concurrent.atomic.AtomicInteger;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
index 31cf223428..2f30f260c9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java
@@ -79,7 +79,7 @@ class MessageTransferHeader implements AMQMessageHeader
public byte getPriority()
{
- MessageDeliveryPriority priority = _deliveryProps == null
+ MessageDeliveryPriority priority = _deliveryProps == null || !_deliveryProps.hasPriority()
? MessageDeliveryPriority.MEDIUM
: _deliveryProps.getPriority();
return (byte) priority.getValue();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties
index aaab4f76cc..badeffca05 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties
@@ -75,6 +75,7 @@ org.apache.qpid.server.exchange=0.0.0
org.apache.qpid.server.logging=0.0.0
org.apache.qpid.server.logging.actors=0.0.0
org.apache.qpid.server.logging.subjects=0.0.0
+org.apache.qpid.server.message=0.0.0
org.apache.qpid.server.management=0.0.0
org.apache.qpid.server.persistent=0.0.0
org.apache.qpid.server.plugins=0.0.0
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index b960ce8608..4e5088808a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.server.protocol;
+import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -36,36 +37,17 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
-
import javax.management.JMException;
import javax.security.auth.Subject;
import javax.security.sasl.SaslServer;
-
import org.apache.log4j.Logger;
import org.apache.qpid.AMQChannelException;
import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.codec.AMQCodecFactory;
-import org.apache.qpid.codec.AMQDecoder;
import org.apache.qpid.common.ClientProperties;
-import org.apache.qpid.framing.AMQBody;
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.framing.AMQFrame;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.framing.AMQProtocolHeaderException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.ChannelCloseBody;
-import org.apache.qpid.framing.ChannelCloseOkBody;
-import org.apache.qpid.framing.ConnectionCloseBody;
-import org.apache.qpid.framing.ContentBody;
-import org.apache.qpid.framing.ContentHeaderBody;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.HeartbeatBody;
-import org.apache.qpid.framing.MethodDispatcher;
-import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.framing.ProtocolInitiation;
-import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.framing.*;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.AMQMethodEvent;
import org.apache.qpid.protocol.AMQMethodListener;
@@ -87,11 +69,15 @@ import org.apache.qpid.server.management.Managable;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.output.ProtocolOutputConverter;
import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.stats.StatisticsCounter;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionImpl;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
import org.apache.qpid.transport.Sender;
@@ -139,7 +125,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
/* AMQP Version for this session */
private ProtocolVersion _protocolVersion = ProtocolVersion.getLatestSupportedVersion();
-
+ private MethodRegistry _methodRegistry = MethodRegistry.getMethodRegistry(_protocolVersion);
private FieldTable _clientProperties;
private final List<Task> _taskList = new CopyOnWriteArrayList<Task>();
@@ -173,6 +159,9 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
private NetworkConnection _network;
private Sender<ByteBuffer> _sender;
+ private volatile boolean _deferFlush;
+ private long _lastReceivedTime;
+
public ManagedObject getManagedObject()
{
return _managedObject;
@@ -240,14 +229,29 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
return _closing.get();
}
+ public synchronized void flushBatched()
+ {
+ _sender.flush();
+ }
+
+
+ public ClientDeliveryMethod createDeliveryMethod(int channelId)
+ {
+ return new WriteDeliverMethod(channelId);
+ }
+
public void received(final ByteBuffer msg)
{
- _lastIoTime = System.currentTimeMillis();
+ final long arrivalTime = System.currentTimeMillis();
+ _lastReceivedTime = arrivalTime;
+ _lastIoTime = arrivalTime;
try
{
final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg);
- for (AMQDataBlock dataBlock : dataBlocks)
+ final int len = dataBlocks.size();
+ for (int i = 0; i < len; i++)
{
+ AMQDataBlock dataBlock = dataBlocks.get(i);
try
{
dataBlockReceived(dataBlock);
@@ -347,7 +351,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
}
}
- private void protocolInitiationReceived(ProtocolInitiation pi)
+ private synchronized void protocolInitiationReceived(ProtocolInitiation pi)
{
// this ensures the codec never checks for a PI message again
(_codecFactory.getDecoder()).setExpectProtocolInitiation(false);
@@ -524,12 +528,15 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
*/
public synchronized void writeFrame(AMQDataBlock frame)
{
- _lastSent = frame;
+
final ByteBuffer buf = asByteBuffer(frame);
- _lastIoTime = System.currentTimeMillis();
_writtenBytes += buf.remaining();
_sender.send(buf);
- _sender.flush();
+ _lastIoTime = System.currentTimeMillis();
+ if(!_deferFlush)
+ {
+ _sender.flush();
+ }
}
public AMQShortString getContextKey()
@@ -918,7 +925,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
private void setProtocolVersion(ProtocolVersion pv)
{
_protocolVersion = pv;
-
+ _methodRegistry = MethodRegistry.getMethodRegistry(_protocolVersion);
_protocolOutputConverter = ProtocolOutputConverterRegistry.getConverter(this);
_dispatcher = ServerMethodDispatcherImpl.createMethodDispatcher(_stateManager, _protocolVersion);
}
@@ -1023,7 +1030,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
public MethodRegistry getMethodRegistry()
{
- return MethodRegistry.getMethodRegistry(getProtocolVersion());
+ return _methodRegistry;
}
public MethodDispatcher getMethodDispatcher()
@@ -1052,7 +1059,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
// Nothing
}
- public void writerIdle()
+ public synchronized void writerIdle()
{
_sender.send(asByteBuffer(HeartbeatBody.FRAME));
}
@@ -1109,6 +1116,11 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
return _lastIoTime;
}
+ public long getLastReceivedTime()
+ {
+ return _lastReceivedTime;
+ }
+
public ProtocolSessionIdentifier getSessionIdentifier()
{
return _sessionIdentifier;
@@ -1395,16 +1407,220 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr
_statisticsEnabled = enabled;
}
- @Override
public boolean isSessionNameUnique(byte[] name)
{
// 0-8/0-9/0-9-1 sessions don't have names
return true;
}
- @Override
+ public void setDeferFlush(boolean deferFlush)
+ {
+ _deferFlush = deferFlush;
+ }
+
+
+
public String getUserName()
{
return getAuthorizedPrincipal().getName();
}
+
+ private static class ByteBufferOutputStream extends OutputStream
+ {
+
+
+ private final ByteBuffer _buf;
+
+ public ByteBufferOutputStream(ByteBuffer buf)
+ {
+ _buf = buf;
+ }
+
+ @Override
+ public void write(int b) throws IOException
+ {
+ _buf.put((byte) b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ _buf.put(b, off, len);
+ }
+ }
+
+ public final class WriteDeliverMethod
+ implements ClientDeliveryMethod
+ {
+ private final int _channelId;
+
+ public WriteDeliverMethod(int channelId)
+ {
+ _channelId = channelId;
+ }
+
+ public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
+ throws AMQException
+ {
+ registerMessageDelivered(entry.getMessage().getSize());
+ _protocolOutputConverter.writeDeliver(entry, _channelId, deliveryTag, ((SubscriptionImpl)sub).getConsumerTag());
+ entry.incrementDeliveryCount();
+ }
+
+ }
+
+ private static class BytesDataOutput implements DataOutput
+ {
+ int _pos = 0;
+ byte[] _buf;
+
+ public BytesDataOutput(byte[] buf)
+ {
+ _buf = buf;
+ }
+
+ public void setBuffer(byte[] buf)
+ {
+ _buf = buf;
+ _pos = 0;
+ }
+
+ public void reset()
+ {
+ _pos = 0;
+ }
+
+ public int length()
+ {
+ return _pos;
+ }
+
+ public void write(int b)
+ {
+ _buf[_pos++] = (byte) b;
+ }
+
+ public void write(byte[] b)
+ {
+ System.arraycopy(b, 0, _buf, _pos, b.length);
+ _pos+=b.length;
+ }
+
+
+ public void write(byte[] b, int off, int len)
+ {
+ System.arraycopy(b, off, _buf, _pos, len);
+ _pos+=len;
+
+ }
+
+ public void writeBoolean(boolean v)
+ {
+ _buf[_pos++] = v ? (byte) 1 : (byte) 0;
+ }
+
+ public void writeByte(int v)
+ {
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeShort(int v)
+ {
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeChar(int v)
+ {
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeInt(int v)
+ {
+ _buf[_pos++] = (byte) (v >>> 24);
+ _buf[_pos++] = (byte) (v >>> 16);
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+
+ public void writeLong(long v)
+ {
+ _buf[_pos++] = (byte) (v >>> 56);
+ _buf[_pos++] = (byte) (v >>> 48);
+ _buf[_pos++] = (byte) (v >>> 40);
+ _buf[_pos++] = (byte) (v >>> 32);
+ _buf[_pos++] = (byte) (v >>> 24);
+ _buf[_pos++] = (byte) (v >>> 16);
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte)v;
+ }
+
+ public void writeFloat(float v)
+ {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ public void writeDouble(double v)
+ {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ public void writeBytes(String s)
+ {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++)
+ {
+ _buf[_pos++] = ((byte)s.charAt(i));
+ }
+ }
+
+ public void writeChars(String s)
+ {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++)
+ {
+ int v = s.charAt(i);
+ _buf[_pos++] = (byte) (v >>> 8);
+ _buf[_pos++] = (byte) v;
+ }
+ }
+
+ public void writeUTF(String s)
+ {
+ int strlen = s.length();
+
+ int pos = _pos;
+ _pos+=2;
+
+
+ for (int i = 0; i < strlen; i++)
+ {
+ int c = s.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F))
+ {
+ c = s.charAt(i);
+ _buf[_pos++] = (byte) c;
+
+ }
+ else if (c > 0x07FF)
+ {
+ _buf[_pos++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+ _buf[_pos++] = (byte) (0x80 | ((c >> 6) & 0x3F));
+ _buf[_pos++] = (byte) (0x80 | (c & 0x3F));
+ }
+ else
+ {
+ _buf[_pos++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+ _buf[_pos++] = (byte) (0x80 | (c & 0x3F));
+ }
+ }
+
+ int len = _pos - (pos + 2);
+
+ _buf[pos++] = (byte) (len >>> 8);
+ _buf[pos] = (byte) len;
+ }
+
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
index c1b5b02f8f..dfba10750c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java
@@ -32,6 +32,7 @@ import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.security.AuthorizationHolder;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.subscription.ClientDeliveryMethod;
import org.apache.qpid.server.virtualhost.VirtualHost;
import java.util.List;
@@ -49,6 +50,14 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Auth
boolean isClosing();
+ void flushBatched();
+
+ void setDeferFlush(boolean defer);
+
+ ClientDeliveryMethod createDeliveryMethod(int channelId);
+
+ long getLastReceivedTime();
+
public static final class ProtocolSessionIdentifier
{
private final Object _sessionIdentifier;
@@ -77,15 +86,6 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Auth
}
/**
- * Called when a protocol data block is received
- *
- * @param message the data block that has been received
- *
- * @throws Exception if processing the datablock fails
- */
- void dataBlockReceived(AMQDataBlock message) throws Exception;
-
- /**
* Get the context key associated with this session. Context key is described in the AMQ protocol specification (RFC
* 6).
*
@@ -234,4 +234,5 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, Auth
List<AMQChannel> getChannels();
void mgmtCloseChannel(int channelId);
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
index 16d99de492..8d39420631 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java
@@ -39,89 +39,44 @@ package org.apache.qpid.server.protocol;
import java.util.Date;
import java.util.List;
-
import javax.management.JMException;
import javax.management.MBeanException;
-import javax.management.MBeanNotificationInfo;
import javax.management.NotCompliantMBeanException;
-import javax.management.Notification;
-import javax.management.ObjectName;
-import javax.management.monitor.MonitorNotification;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
-import javax.management.openmbean.TabularType;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.ConnectionCloseBody;
import org.apache.qpid.framing.MethodRegistry;
-import org.apache.qpid.management.common.mbeans.ManagedConnection;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.ManagementActor;
-import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.management.AbstractAMQManagedConnectionObject;
import org.apache.qpid.server.management.ManagedObject;
/**
* This MBean class implements the management interface. In order to make more attributes, operations and notifications
* available over JMX simply augment the ManagedConnection interface and add the appropriate implementation here.
*/
-@MBeanDescription("Management Bean for an AMQ Broker Connection")
-public class AMQProtocolSessionMBean extends AMQManagedObject implements ManagedConnection
+@MBeanDescription("Management Bean for an AMQ Broker 0-9-1/0-9/0-8 Connections")
+public class AMQProtocolSessionMBean extends AbstractAMQManagedConnectionObject
{
private AMQProtocolSession _protocolSession = null;
- private String _name = null;
- // openmbean data types for representing the channel attributes
-
- private static final OpenType[] _channelAttributeTypes =
- { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN };
- private static CompositeType _channelType = null; // represents the data type for channel data
- private static TabularType _channelsType = null; // Data type for list of channels type
private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION =
- new AMQShortString("Broker Management Console has closed the connection.");
+ new AMQShortString(BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION_STR);
- @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection")
+ @MBeanConstructor("Creates an MBean exposing an AMQ Broker 0-9-1/0-9/0-8 Connection")
public AMQProtocolSessionMBean(AMQProtocolSession amqProtocolSession) throws NotCompliantMBeanException, OpenDataException
{
- super(ManagedConnection.class, ManagedConnection.TYPE);
+ super(amqProtocolSession.getRemoteAddress().toString());
_protocolSession = amqProtocolSession;
- String remote = getRemoteAddress();
- _name = "anonymous".equals(remote) ? (remote + hashCode()) : remote;
- init();
- }
-
- static
- {
- try
- {
- init();
- }
- catch (JMException ex)
- {
- // This is not expected to ever occur.
- throw new RuntimeException("Got JMException in static initializer.", ex);
- }
- }
-
- /**
- * initialises the openmbean data types
- */
- private static void init() throws OpenDataException
- {
- _channelType =
- new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]),
- COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), _channelAttributeTypes);
- _channelsType = new TabularType("Channels", "Channels", _channelType, TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()]));
}
public String getClientId()
@@ -169,16 +124,6 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
return _protocolSession.getMaximumNumberOfChannels();
}
- public void setMaximumNumberOfChannels(Long value)
- {
- _protocolSession.setMaximumNumberOfChannels(value);
- }
-
- public String getObjectInstanceName()
- {
- return ObjectName.quote(_name);
- }
-
/**
* commits transactions for a transactional channel
*
@@ -321,25 +266,6 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed
}
}
- @Override
- public MBeanNotificationInfo[] getNotificationInfo()
- {
- String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED };
- String name = MonitorNotification.class.getName();
- String description = "Channel count has reached threshold value";
- MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description);
-
- return new MBeanNotificationInfo[] { info1 };
- }
-
- public void notifyClients(String notificationMsg)
- {
- Notification n =
- new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber,
- System.currentTimeMillis(), notificationMsg);
- _broadcaster.sendNotification(n);
- }
-
public void resetStatistics() throws Exception
{
_protocolSession.resetStatistics();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
index 48a8a1bf42..5d4b8c603b 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java
@@ -100,6 +100,12 @@ public class ProtocolEngine_0_10 extends InputHandler implements ServerProtocol
return _network.getLocalAddress();
}
+ public void received(final ByteBuffer buf)
+ {
+ super.received(buf);
+ _connection.receivedComplete();
+ }
+
public long getReadBytes()
{
return _readBytes;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
index a9ddf9bb0c..dd4bd2bb1c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
@@ -20,6 +20,14 @@
*/
package org.apache.qpid.server.protocol.v1_0;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.qpid.AMQException;
import org.apache.qpid.AMQInternalException;
import org.apache.qpid.AMQInvalidArgumentException;
import org.apache.qpid.AMQSecurityException;
@@ -27,16 +35,28 @@ import org.apache.qpid.amqp_1_0.transport.DeliveryStateHandler;
import org.apache.qpid.amqp_1_0.transport.LinkEndpoint;
import org.apache.qpid.amqp_1_0.transport.SendingLinkEndpoint;
import org.apache.qpid.amqp_1_0.transport.SendingLinkListener;
-import org.apache.qpid.amqp_1_0.type.*;
-
-import org.apache.qpid.amqp_1_0.type.messaging.*;
+import org.apache.qpid.amqp_1_0.type.AmqpErrorException;
+import org.apache.qpid.amqp_1_0.type.Binary;
+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.JMSSelectorFilter;
+import org.apache.qpid.amqp_1_0.type.messaging.MatchingSubjectFilter;
+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.transport.*;
-import org.apache.qpid.AMQException;
+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.transport.AmqpError;
+import org.apache.qpid.amqp_1_0.type.transport.Detach;
import org.apache.qpid.amqp_1_0.type.transport.Error;
+import org.apache.qpid.amqp_1_0.type.transport.Transfer;
import org.apache.qpid.server.exchange.DirectExchange;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.exchange.ExchangeType;
import org.apache.qpid.server.exchange.TopicExchange;
import org.apache.qpid.server.filter.JMSSelectorMessageFilter;
import org.apache.qpid.server.filter.SimpleFilterManager;
@@ -47,9 +67,6 @@ import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryStateHandler
{
private VirtualHost _vhost;
@@ -140,7 +157,7 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS
try
{
queue = AMQQueueFactory.createAMQQueueImpl(UUID.randomUUID().toString(), false, null, true,
- false, _vhost, Collections.EMPTY_MAP);
+ false, _vhost, Collections.EMPTY_MAP);
Exchange exchange = ((ExchangeDestination) destination).getExchange();
String binding = "";
@@ -183,6 +200,9 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS
catch (AMQInternalException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ } catch (AMQException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
index 4b189652d3..e08e7f3e39 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
@@ -365,6 +365,9 @@ public class Session_1_0 implements SessionEventListener
catch (AMQSecurityException e)
{
e.printStackTrace(); //TODO.
+ } catch (AMQException e)
+ {
+ e.printStackTrace(); //TODO
}
return queue;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
index fc64527f3b..5dea91b6d4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java
@@ -20,6 +20,13 @@
*/
package org.apache.qpid.server.protocol.v1_0;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.qpid.AMQException;
import org.apache.qpid.amqp_1_0.transport.SendingLinkEndpoint;
import org.apache.qpid.amqp_1_0.type.Binary;
import org.apache.qpid.amqp_1_0.type.DeliveryState;
@@ -31,24 +38,14 @@ import org.apache.qpid.amqp_1_0.type.messaging.StdDistMode;
import org.apache.qpid.amqp_1_0.type.transaction.TransactionalState;
import org.apache.qpid.amqp_1_0.type.transport.SenderSettleMode;
import org.apache.qpid.amqp_1_0.type.transport.Transfer;
-
-import org.apache.qpid.AMQException;
import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.logging.LogActor;
-import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.txn.ServerTransaction;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.ReentrantLock;
-
class Subscription_1_0 implements Subscription
{
private SendingLink_1_0 _link;
@@ -171,6 +168,17 @@ class Subscription_1_0 implements Subscription
getEndpoint().detach();
}
+ public void send(QueueEntry entry, boolean batch) throws AMQException
+ {
+ // TODO
+ send(entry);
+ }
+
+ public void flushBatched()
+ {
+ // TODO
+ }
+
public void send(final QueueEntry queueEntry) throws AMQException
{
//TODO
@@ -296,6 +304,11 @@ class Subscription_1_0 implements Subscription
return !hasCredit;
}
+ public boolean trySendLock()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void suspend()
{
if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED))
@@ -314,6 +327,11 @@ class Subscription_1_0 implements Subscription
_stateChangeLock.unlock();
}
+ public void releaseQueueEntry(QueueEntry queueEntryImpl)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
public void onDequeue(final QueueEntry queueEntry)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
index 371ae0de50..2c04a626ff 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java
@@ -20,71 +20,25 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.subscription.SubscriptionList;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
import java.util.Map;
+import org.apache.qpid.server.virtualhost.VirtualHost;
-public class AMQPriorityQueue extends SimpleAMQQueue
+public class AMQPriorityQueue extends OutOfOrderQueue
{
- protected AMQPriorityQueue(final AMQShortString name,
- final boolean durable,
- final AMQShortString owner,
- final boolean autoDelete,
- boolean exclusive,
- final VirtualHost virtualHost,
- int priorities, Map<String, Object> arguments)
- {
- super(name, durable, owner, autoDelete, exclusive, virtualHost,new PriorityQueueList.Factory(priorities), arguments);
- }
-
- public AMQPriorityQueue(String queueName,
- boolean durable,
- String owner,
- boolean autoDelete,
- boolean exclusive, VirtualHost virtualHost, int priorities, Map<String,Object> arguments)
+ protected AMQPriorityQueue(final String name,
+ final boolean durable,
+ final String owner,
+ final boolean autoDelete,
+ boolean exclusive,
+ final VirtualHost virtualHost,
+ Map<String, Object> arguments,
+ int priorities)
{
- this(queueName == null ? null : new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),
- autoDelete, exclusive,virtualHost, priorities, arguments);
+ super(name, durable, owner, autoDelete, exclusive, virtualHost, new PriorityQueueList.Factory(priorities), arguments);
}
public int getPriorities()
{
return ((PriorityQueueList) _entries).getPriorities();
}
-
- @Override
- protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry)
- {
- // check that all subscriptions are not in advance of the entry
- SubscriptionList.SubscriptionNodeIterator subIter = _subscriptionList.iterator();
- while(subIter.advance() && entry.isAvailable())
- {
- final Subscription subscription = subIter.getNode().getSubscription();
- if(!subscription.isClosed())
- {
- QueueContext context = (QueueContext) subscription.getQueueContext();
- if(context != null)
- {
- QueueEntry subnode = context._lastSeenEntry;
- QueueEntry released = context._releasedEntry;
- while(subnode != null && entry.compareTo(subnode) < 0 && entry.isAvailable() && (released == null || released.compareTo(entry) < 0))
- {
- if(QueueContext._releasedUpdater.compareAndSet(context,released,entry))
- {
- break;
- }
- else
- {
- subnode = context._lastSeenEntry;
- released = context._releasedEntry;
- }
- }
- }
- }
-
- }
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index 9140a13625..6dfdc5e8b4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -213,6 +213,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer
void setAlternateExchange(Exchange exchange);
+ void setAlternateExchange(String exchangeName);
+
Map<String, Object> getArguments();
void checkCapacity(AMQChannel channel);
@@ -272,4 +274,22 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer
ManagedObject getManagedObject();
void setExclusive(boolean exclusive) throws AMQException;
+
+ /**
+ * Gets the maximum delivery count. If a message on this queue
+ * is delivered more than maximumDeliveryCount, the message will be
+ * routed to the {@link #getAlternateExchange()} (if set), or otherwise
+ * discarded. 0 indicates that maximum deliver count should not be enforced.
+ *
+ * @return maximum delivery count
+ */
+ int getMaximumDeliveryCount();
+
+ /**
+ * Sets the maximum delivery count.
+ *
+ * @param maximumDeliveryCount maximum delivery count
+ */
+ public void setMaximumDeliveryCount(final int maximumDeliveryCount);
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
index 5fbad74978..14ca147982 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
@@ -20,22 +20,33 @@
*/
package org.apache.qpid.server.queue;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.configuration.QueueConfiguration;
-
-import java.util.Map;
-import java.util.HashMap;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.ExchangeFactory;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
public class AMQQueueFactory
{
- public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities");
+ public static final String X_QPID_PRIORITIES = "x-qpid-priorities";
public static final String QPID_LVQ_KEY = "qpid.LVQ_key";
public static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue";
public static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key";
+ public static final String QPID_QUEUE_SORT_KEY = "qpid.queue_sort_key";
+
+ public static final String DLQ_ROUTING_KEY = "dlq";
+ public static final String X_QPID_DLQ_ENABLED = "x-qpid-dlq-enabled";
+ public static final String X_QPID_MAXIMUM_DELIVERY_COUNT = "x-qpid-maximum-delivery-count";
+ public static final String DEFAULT_DLQ_NAME_SUFFIX = "_DLQ";
private abstract static class QueueProperty
{
@@ -80,6 +91,24 @@ public class AMQQueueFactory
}
+ private abstract static class QueueIntegerProperty extends QueueProperty
+ {
+ public QueueIntegerProperty(String argumentName)
+ {
+ super(argumentName);
+ }
+
+ public void setPropertyValue(AMQQueue queue, Object value)
+ {
+ if(value instanceof Number)
+ {
+ setPropertyValue(queue, ((Number)value).intValue());
+ }
+
+ }
+ abstract void setPropertyValue(AMQQueue queue, int value);
+ }
+
private static final QueueProperty[] DECLAREABLE_PROPERTIES = {
new QueueLongProperty("x-qpid-maximum-message-age")
{
@@ -122,8 +151,14 @@ public class AMQQueueFactory
{
queue.setFlowResumeCapacity(value);
}
+ },
+ new QueueIntegerProperty(X_QPID_MAXIMUM_DELIVERY_COUNT)
+ {
+ public void setPropertyValue(AMQQueue queue, int value)
+ {
+ queue.setMaximumDeliveryCount(value);
+ }
}
-
};
@@ -149,17 +184,31 @@ public class AMQQueueFactory
String owner,
boolean autoDelete,
boolean exclusive,
- VirtualHost virtualHost, Map<String, Object> arguments) throws AMQSecurityException
+ VirtualHost virtualHost, Map<String, Object> arguments) throws AMQSecurityException, AMQException
{
+ if (queueName == null)
+ {
+ throw new IllegalArgumentException("Queue name must not be null");
+ }
+
// Access check
if (!virtualHost.getSecurityManager().authoriseCreateQueue(autoDelete, durable, exclusive, null, null, new AMQShortString(queueName), owner))
{
String description = "Permission denied: queue-name '" + queueName + "'";
throw new AMQSecurityException(description);
}
-
+
+ QueueConfiguration queueConfiguration = virtualHost.getConfiguration().getQueueConfiguration(queueName);
+ boolean isDLQEnabled = isDLQEnabled(autoDelete, arguments, queueConfiguration);
+ if (isDLQEnabled)
+ {
+ validateDLNames(queueName);
+ }
+
int priorities = 1;
String conflationKey = null;
+ String sortingKey = null;
+
if(arguments != null)
{
if(arguments.containsKey(QPID_LAST_VALUE_QUEUE) || arguments.containsKey(QPID_LAST_VALUE_QUEUE_KEY))
@@ -170,24 +219,32 @@ public class AMQQueueFactory
conflationKey = QPID_LVQ_KEY;
}
}
- else if(arguments.containsKey(X_QPID_PRIORITIES.toString()))
+ else if(arguments.containsKey(X_QPID_PRIORITIES))
{
- Object prioritiesObj = arguments.get(X_QPID_PRIORITIES.toString());
+ Object prioritiesObj = arguments.get(X_QPID_PRIORITIES);
if(prioritiesObj instanceof Number)
{
priorities = ((Number)prioritiesObj).intValue();
}
}
+ else if(arguments.containsKey(QPID_QUEUE_SORT_KEY))
+ {
+ sortingKey = (String)arguments.get(QPID_QUEUE_SORT_KEY);
+ }
}
AMQQueue q;
- if(conflationKey != null)
+ if(sortingKey != null)
+ {
+ q = new SortedQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, sortingKey);
+ }
+ else if(conflationKey != null)
{
q = new ConflationQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, conflationKey);
}
else if(priorities > 1)
{
- q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, priorities, arguments);
+ q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, exclusive, virtualHost, arguments, priorities);
}
else
{
@@ -209,10 +266,63 @@ public class AMQQueueFactory
}
}
- return q;
+ if(isDLQEnabled)
+ {
+ final String dlExchangeName = getDeadLetterExchangeName(queueName);
+ final String dlQueueName = getDeadLetterQueueName(queueName);
- }
+ final ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
+ final ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory();
+ final QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
+
+ Exchange dlExchange = null;
+ synchronized(exchangeRegistry)
+ {
+ dlExchange = exchangeRegistry.getExchange(dlExchangeName);
+
+ if(dlExchange == null)
+ {
+ dlExchange = exchangeFactory.createExchange(new AMQShortString(dlExchangeName), ExchangeDefaults.FANOUT_EXCHANGE_CLASS, true, false, 0);
+
+ exchangeRegistry.registerExchange(dlExchange);
+
+ //enter the dle in the persistent store
+ virtualHost.getDurableConfigurationStore().createExchange(dlExchange);
+ }
+ }
+
+ AMQQueue dlQueue = null;
+
+ synchronized(queueRegistry)
+ {
+ dlQueue = queueRegistry.getQueue(dlQueueName);
+
+ if(dlQueue == null)
+ {
+ //set args to disable DLQ'ing/MDC from the DLQ itself, preventing loops etc
+ final Map<String, Object> args = new HashMap<String, Object>();
+ args.put(X_QPID_DLQ_ENABLED, false);
+ args.put(X_QPID_MAXIMUM_DELIVERY_COUNT, 0);
+
+ dlQueue = createAMQQueueImpl(dlQueueName, true, owner, false, exclusive, virtualHost, args);
+ //enter the dlq in the persistent store
+ virtualHost.getDurableConfigurationStore().createQueue(dlQueue, FieldTable.convertToFieldTable(args));
+ }
+ }
+
+ //ensure the queue is bound to the exchange
+ if(!dlExchange.isBound(DLQ_ROUTING_KEY, dlQueue))
+ {
+ //actual routing key used does not matter due to use of fanout exchange,
+ //but we will make the key 'dlq' as it can be logged at creation.
+ virtualHost.getBindingFactory().addBinding(DLQ_ROUTING_KEY, dlQueue, dlExchange, null);
+ }
+ q.setAlternateExchange(dlExchange);
+ }
+
+ return q;
+ }
public static AMQQueue createAMQQueueImpl(QueueConfiguration config, VirtualHost host) throws AMQException
{
@@ -223,26 +333,30 @@ public class AMQQueueFactory
boolean exclusive = config.getExclusive();
String owner = config.getOwner();
Map<String,Object> arguments = null;
+
if(config.isLVQ() || config.getLVQKey() != null)
{
-
arguments = new HashMap<String,Object>();
arguments.put(QPID_LAST_VALUE_QUEUE, 1);
arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey());
}
- else
+ else if (config.getPriority() || config.getPriorities() > 0)
+ {
+ arguments = new HashMap<String,Object>();
+ arguments.put(X_QPID_PRIORITIES, config.getPriorities() < 0 ? 10 : config.getPriorities());
+ }
+ else if (config.getQueueSortKey() != null && !"".equals(config.getQueueSortKey()))
+ {
+ arguments = new HashMap<String,Object>();
+ arguments.put(QPID_QUEUE_SORT_KEY, config.getQueueSortKey());
+ }
+ if (!config.getAutoDelete() && config.isDeadLetterQueueEnabled())
{
- boolean priority = config.getPriority();
- int priorities = config.getPriorities();
- if(priority || priorities > 0)
+ if (arguments == null)
{
arguments = new HashMap<String,Object>();
- if (priorities < 0)
- {
- priorities = 10;
- }
- arguments.put("x-qpid-priorities", priorities);
}
+ arguments.put(X_QPID_DLQ_ENABLED, true);
}
if(config.isTopic())
@@ -259,4 +373,94 @@ public class AMQQueueFactory
return q;
}
+
+ /**
+ * Validates DLQ and DLE names
+ * <p>
+ * DLQ name and DLQ exchange name need to be validated in order to keep
+ * integrity in cases when queue name passes validation check but DLQ name
+ * or DL exchange name fails to pass it. Otherwise, we might have situations
+ * when queue is created but DL exchange or/and DLQ creation fail.
+ * <p>
+ *
+ * @param name
+ * queue name
+ * @throws IllegalArgumentException
+ * thrown if length of queue name or exchange name exceed 255
+ */
+ protected static void validateDLNames(String name)
+ {
+ // check if DLQ name and DLQ exchange name do not exceed 255
+ String exchangeName = getDeadLetterExchangeName(name);
+ if (exchangeName.length() > AMQShortString.MAX_LENGTH)
+ {
+ throw new IllegalArgumentException("DL exchange name '" + exchangeName
+ + "' length exceeds limit of " + AMQShortString.MAX_LENGTH + " characters for queue " + name);
+ }
+ String queueName = getDeadLetterQueueName(name);
+ if (queueName.length() > AMQShortString.MAX_LENGTH)
+ {
+ throw new IllegalArgumentException("DLQ queue name '" + queueName + "' length exceeds limit of "
+ + AMQShortString.MAX_LENGTH + " characters for queue " + name);
+ }
+ }
+
+ /**
+ * Checks if DLQ is enabled for the queue.
+ *
+ * @param autoDelete
+ * queue auto-delete flag
+ * @param arguments
+ * queue arguments
+ * @param qConfig
+ * queue configuration
+ * @return true if DLQ enabled
+ */
+ protected static boolean isDLQEnabled(boolean autoDelete, Map<String, Object> arguments, QueueConfiguration qConfig)
+ {
+ //feature is not to be enabled for temporary queues or when explicitly disabled by argument
+ if (!autoDelete)
+ {
+ boolean dlqArgumentPresent = arguments != null && arguments.containsKey(X_QPID_DLQ_ENABLED);
+ if (dlqArgumentPresent || qConfig.isDeadLetterQueueEnabled())
+ {
+ boolean dlqEnabled = true;
+ if (dlqArgumentPresent)
+ {
+ Object argument = arguments.get(X_QPID_DLQ_ENABLED);
+ dlqEnabled = argument instanceof Boolean && ((Boolean)argument).booleanValue();
+ }
+ return dlqEnabled;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Generates a dead letter queue name for a given queue name
+ *
+ * @param name
+ * queue name
+ * @return DLQ name
+ */
+ protected static String getDeadLetterQueueName(String name)
+ {
+ ServerConfiguration serverConfig = ApplicationRegistry.getInstance().getConfiguration();
+ String dlQueueName = name + serverConfig.getDeadLetterQueueSuffix();
+ return dlQueueName;
+ }
+
+ /**
+ * Generates a dead letter exchange name for a given queue name
+ *
+ * @param name
+ * queue name
+ * @return DL exchange name
+ */
+ protected static String getDeadLetterExchangeName(String name)
+ {
+ ServerConfiguration serverConfig = ApplicationRegistry.getInstance().getConfiguration();
+ String dlExchangeName = name + serverConfig.getDeadLetterExchangeSuffix();
+ return dlExchangeName;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index c8eb118b11..b4765d6227 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -28,7 +28,7 @@ import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
-import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.message.ServerMessage;
@@ -63,23 +63,25 @@ import java.util.*;
/**
* AMQQueueMBean is the management bean for an {@link AMQQueue}.
*
- * <p/><tablse id="crc"><caption>CRC Caption</caption>
+ * <p/><table id="crc"><caption>CRC Caption</caption>
* <tr><th> Responsibilities <th> Collaborations
* </table>
*/
@MBeanDescription("Management Interface for AMQQueue")
public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener
{
+
/** Used for debugging purposes. */
private static final Logger _logger = Logger.getLogger(AMQQueueMBean.class);
- private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z");
+ /** Date/time format used for message expiration and message timestamp formatting */
+ public static final String JMSTIMESTAMP_DATETIME_FORMAT = "MM-dd-yy HH:mm:ss.SSS z";
- private AMQQueue _queue = null;
- private String _queueName = null;
+ private final AMQQueue _queue;
+ private final String _queueName;
// OpenMBean data types for viewMessages method
- private static OpenType[] _msgAttributeTypes = new OpenType[5]; // AMQ message attribute types.
+ private static OpenType[] _msgAttributeTypes = new OpenType[6]; // AMQ message attribute types.
private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data.
private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list.
@@ -138,6 +140,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
_msgAttributeTypes[2] = SimpleType.LONG; // For size
_msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered
_msgAttributeTypes[4] = SimpleType.LONG; // For queue position
+ _msgAttributeTypes[5] = SimpleType.INTEGER; // For delivery count
_messageDataType = new CompositeType("Message", "AMQ Message",
VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]),
@@ -176,6 +179,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
return _queue.getMessageCount();
}
+ public Integer getMaximumDeliveryCount()
+ {
+ return _queue.getMaximumDeliveryCount();
+ }
+
public Long getMaximumMessageSize()
{
return _queue.getMaximumMessageSize();
@@ -294,6 +302,18 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
}
}
+ public void setAlternateExchange(String exchangeName)
+ {
+ _queue.setAlternateExchange(exchangeName);
+ }
+
+ public String getAlternateExchange()
+ {
+ Exchange exchange = _queue.getAlternateExchange();
+ String name = exchange == null ? null : exchange.getName();
+ return name == null ? null : name;
+ }
+
/**
* Checks if there is any notification to be send to the listeners
*/
@@ -471,7 +491,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
ContentHeaderBody headerBody = msg.getContentHeaderBody();
// Create header attributes list
headerAttributes = getMessageHeaderProperties(headerBody);
- itemValues = new Object[]{msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position};
+ itemValues = new Object[]{msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()};
}
else if(serverMsg instanceof MessageTransferMessage)
{
@@ -480,13 +500,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
// Create header attributes list
headerAttributes = getMessageTransferMessageHeaderProps(msg);
- itemValues = new Object[]{msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position};
+ itemValues = new Object[]{msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()};
}
else
{
//unknown message
headerAttributes = new String[]{"N/A"};
- itemValues = new Object[]{serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position};
+ itemValues = new Object[]{serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()};
}
CompositeData messageData = new CompositeDataSupport(_messageDataType,
@@ -523,13 +543,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
list.add("JMSPriority = " + headerProperties.getPriority());
list.add("JMSType = " + headerProperties.getType());
- long longDate = headerProperties.getExpiration();
- String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSExpiration = " + strDate);
+ final long expirationDate = headerProperties.getExpiration();
+ final long timestampDate = headerProperties.getTimestamp();
- longDate = headerProperties.getTimestamp();
- strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSTimestamp = " + strDate);
+ addStringifiedJMSTimestamoAndJMSExpiration(list, expirationDate,
+ timestampDate);
return list.toArray(new String[list.size()]);
}
@@ -561,17 +579,32 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
list.add("JMSPriority = " + header.getPriority());
list.add("JMSType = " + header.getType());
- long longDate = header.getExpiration();
- String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSExpiration = " + strDate);
-
- longDate = header.getTimestamp();
- strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null;
- list.add("JMSTimestamp = " + strDate);
+ final long expirationDate = header.getExpiration();
+ final long timestampDate = header.getTimestamp();
+ addStringifiedJMSTimestamoAndJMSExpiration(list, expirationDate, timestampDate);
return list.toArray(new String[list.size()]);
}
+ private void addStringifiedJMSTimestamoAndJMSExpiration(final List<String> list,
+ final long expirationDate, final long timestampDate)
+ {
+ final SimpleDateFormat dateFormat;
+ if (expirationDate != 0 || timestampDate != 0)
+ {
+ dateFormat = new SimpleDateFormat(JMSTIMESTAMP_DATETIME_FORMAT);
+ }
+ else
+ {
+ dateFormat = null;
+ }
+
+ final String formattedExpirationDate = (expirationDate != 0) ? dateFormat.format(new Date(expirationDate)) : null;
+ final String formattedTimestampDate = (timestampDate != 0) ? dateFormat.format(new Date(timestampDate)) : null;
+ list.add("JMSExpiration = " + formattedExpirationDate);
+ list.add("JMSTimestamp = " + formattedTimestampDate);
+ }
+
/**
* @see ManagedQueue#moveMessages
* @param fromMessageId
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
index 2c1883e763..c4762c98c9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
@@ -54,7 +54,7 @@ public class ConflationQueueList extends SimpleQueueEntryList
@Override
- public QueueEntry add(final ServerMessage message)
+ public ConflationQueueEntry add(final ServerMessage message)
{
ConflationQueueEntry entry = (ConflationQueueEntry) (super.add(message));
AtomicReference<QueueEntry> latestValueReference = null;
@@ -117,7 +117,7 @@ public class ConflationQueueList extends SimpleQueueEntryList
}
}
- private final class ConflationQueueEntry extends QueueEntryImpl
+ private final class ConflationQueueEntry extends SimpleQueueEntryImpl
{
@@ -158,7 +158,7 @@ public class ConflationQueueList extends SimpleQueueEntryList
_conflationKey = conflationKey;
}
- public QueueEntryList createQueueEntryList(AMQQueue queue)
+ public ConflationQueueList createQueueEntryList(AMQQueue queue)
{
return new ConflationQueueList(queue, _conflationKey);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
index 77da08d8c4..26112d9f53 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
@@ -24,7 +24,7 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.server.message.AMQMessageHeader;
-class InboundMessageAdapter implements InboundMessage
+public class InboundMessageAdapter implements InboundMessage
{
private QueueEntry _entry;
@@ -33,7 +33,7 @@ class InboundMessageAdapter implements InboundMessage
{
}
- InboundMessageAdapter(QueueEntry entry)
+ public InboundMessageAdapter(QueueEntry entry)
{
_entry = entry;
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
new file mode 100644
index 0000000000..b16d1eb8e3
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
@@ -0,0 +1,53 @@
+package org.apache.qpid.server.queue;
+
+import java.util.Map;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionList;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public abstract class OutOfOrderQueue extends SimpleAMQQueue
+{
+ protected OutOfOrderQueue(String name, boolean durable, String owner,
+ boolean autoDelete, boolean exclusive, VirtualHost virtualHost,
+ QueueEntryListFactory entryListFactory, Map<String, Object> arguments)
+ {
+ super(name, durable, owner, autoDelete, exclusive, virtualHost, entryListFactory, arguments);
+ }
+
+ @Override
+ protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry)
+ {
+ // check that all subscriptions are not in advance of the entry
+ SubscriptionList.SubscriptionNodeIterator subIter = _subscriptionList.iterator();
+ while(subIter.advance() && !entry.isAcquired())
+ {
+ final Subscription subscription = subIter.getNode().getSubscription();
+ if(!subscription.isClosed())
+ {
+ QueueContext context = (QueueContext) subscription.getQueueContext();
+ if(context != null)
+ {
+ QueueEntry subnode = context._lastSeenEntry;
+ QueueEntry released = context._releasedEntry;
+
+ while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()
+ && (released == null || released.compareTo(entry) > 0))
+ {
+ if(QueueContext._releasedUpdater.compareAndSet(context,released,entry))
+ {
+ break;
+ }
+ else
+ {
+ subnode = context._lastSeenEntry;
+ released = context._releasedEntry;
+ }
+
+ }
+ }
+ }
+
+ }
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
index 0c6b84d2b6..79d3ab5bd0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java
@@ -20,21 +20,19 @@
*/
package org.apache.qpid.server.queue;
-import org.apache.qpid.framing.CommonContentHeaderProperties;
-import org.apache.qpid.AMQException;
import org.apache.qpid.server.message.ServerMessage;
-public class PriorityQueueList implements QueueEntryList
+public class PriorityQueueList implements QueueEntryList<SimpleQueueEntryImpl>
{
private final AMQQueue _queue;
- private final QueueEntryList[] _priorityLists;
+ private final SimpleQueueEntryList[] _priorityLists;
private final int _priorities;
private final int _priorityOffset;
public PriorityQueueList(AMQQueue queue, int priorities)
{
_queue = queue;
- _priorityLists = new QueueEntryList[priorities];
+ _priorityLists = new SimpleQueueEntryList[priorities];
_priorities = priorities;
_priorityOffset = 5-((priorities + 1)/2);
for(int i = 0; i < priorities; i++)
@@ -53,7 +51,7 @@ public class PriorityQueueList implements QueueEntryList
return _queue;
}
- public QueueEntry add(ServerMessage message)
+ public SimpleQueueEntryImpl add(ServerMessage message)
{
int index = message.getMessageHeader().getPriority() - _priorityOffset;
if(index >= _priorities)
@@ -68,31 +66,30 @@ public class PriorityQueueList implements QueueEntryList
}
- public QueueEntry next(QueueEntry node)
+ public SimpleQueueEntryImpl next(SimpleQueueEntryImpl node)
{
- QueueEntryImpl nodeImpl = (QueueEntryImpl)node;
- QueueEntry next = nodeImpl.getNext();
+ SimpleQueueEntryImpl next = node.getNextValidEntry();
if(next == null)
{
- QueueEntryList nodeEntryList = nodeImpl.getQueueEntryList();
+ final QueueEntryList<?> nodeEntryList = node.getQueueEntryList();
int index;
for(index = _priorityLists.length-1; _priorityLists[index] != nodeEntryList; index--);
while(next == null && index != 0)
{
index--;
- next = ((QueueEntryImpl)_priorityLists[index].getHead()).getNext();
+ next = _priorityLists[index].getHead().getNextValidEntry();
}
}
return next;
}
- private final class PriorityQueueEntryListIterator implements QueueEntryIterator
+ private final class PriorityQueueEntryListIterator implements QueueEntryIterator<SimpleQueueEntryImpl>
{
- private final QueueEntryIterator[] _iterators = new QueueEntryIterator[ _priorityLists.length ];
- private QueueEntry _lastNode;
+ private final SimpleQueueEntryList.QueueEntryIteratorImpl[] _iterators = new SimpleQueueEntryList.QueueEntryIteratorImpl[ _priorityLists.length ];
+ private SimpleQueueEntryImpl _lastNode;
PriorityQueueEntryListIterator()
{
@@ -116,7 +113,7 @@ public class PriorityQueueList implements QueueEntryList
return true;
}
- public QueueEntry getNode()
+ public SimpleQueueEntryImpl getNode()
{
return _lastNode;
}
@@ -135,16 +132,21 @@ public class PriorityQueueList implements QueueEntryList
}
}
- public QueueEntryIterator iterator()
+ public PriorityQueueEntryListIterator iterator()
{
return new PriorityQueueEntryListIterator();
}
- public QueueEntry getHead()
+ public SimpleQueueEntryImpl getHead()
{
return _priorityLists[_priorities-1].getHead();
}
+ public void entryDeleted(final SimpleQueueEntryImpl queueEntry)
+ {
+
+ }
+
static class Factory implements QueueEntryListFactory
{
private final int _priorities;
@@ -154,7 +156,7 @@ public class PriorityQueueList implements QueueEntryList
_priorities = priorities;
}
- public QueueEntryList createQueueEntryList(AMQQueue queue)
+ public PriorityQueueList createQueueEntryList(AMQQueue queue)
{
return new PriorityQueueList(queue, _priorities);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
index be29245901..37fad54c07 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
@@ -1,5 +1,7 @@
package org.apache.qpid.server.queue;
+import java.util.Collection;
+
import org.apache.qpid.AMQException;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.message.ServerMessage;
@@ -214,6 +216,10 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable
boolean isQueueDeleted();
+ QueueEntry getNextNode();
+
+ QueueEntry getNextValidEntry();
+
void addStateChangeListener(StateChangeListener listener);
boolean removeStateChangeListener(StateChangeListener listener);
@@ -230,4 +236,16 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable
* @return true if entry is either DEQUED or DELETED state
*/
boolean isDispensed();
+
+ /**
+ * Number of times this queue entry has been delivered.
+ *
+ * @return delivery count
+ */
+ int getDeliveryCount();
+
+ void incrementDeliveryCount();
+
+ void decrementDeliveryCount();
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index 5b57e40a82..f1e50427b1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -20,8 +20,14 @@
*/
package org.apache.qpid.server.queue;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.apache.log4j.Logger;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.message.AMQMessageHeader;
@@ -31,23 +37,11 @@ import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.txn.AutoCommitTransaction;
import org.apache.qpid.server.txn.ServerTransaction;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.atomic.AtomicLongFieldUpdater;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-
-
-public class QueueEntryImpl implements QueueEntry
+public abstract class QueueEntryImpl implements QueueEntry
{
-
- /**
- * Used for debugging purposes.
- */
private static final Logger _log = Logger.getLogger(QueueEntryImpl.class);
- private final SimpleQueueEntryList _queueEntryList;
+ private final QueueEntryList _queueEntryList;
private MessageReference _message;
@@ -80,22 +74,26 @@ public class QueueEntryImpl implements QueueEntry
private volatile long _entryId;
- volatile QueueEntryImpl _next;
-
private static final int DELIVERED_TO_CONSUMER = 1;
private static final int REDELIVERED = 2;
private volatile int _deliveryState;
+ /** Number of times this message has been delivered */
+ private volatile int _deliveryCount = 0;
+ private static final AtomicIntegerFieldUpdater<QueueEntryImpl> _deliveryCountUpdater = AtomicIntegerFieldUpdater
+ .newUpdater(QueueEntryImpl.class, "_deliveryCount");
+
- QueueEntryImpl(SimpleQueueEntryList queueEntryList)
+
+ public QueueEntryImpl(QueueEntryList<?> queueEntryList)
{
this(queueEntryList,null,Long.MIN_VALUE);
_state = DELETED_STATE;
}
- public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId)
+ public QueueEntryImpl(QueueEntryList<?> queueEntryList, ServerMessage message, final long entryId)
{
_queueEntryList = queueEntryList;
@@ -104,7 +102,7 @@ public class QueueEntryImpl implements QueueEntry
_entryIdUpdater.set(this, entryId);
}
- public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message)
+ public QueueEntryImpl(QueueEntryList<?> queueEntryList, ServerMessage message)
{
_queueEntryList = queueEntryList;
_message = message == null ? null : message.newReference();
@@ -233,8 +231,13 @@ public class QueueEntryImpl implements QueueEntry
if(state instanceof SubscriptionAcquiredState)
{
getQueue().decrementUnackedMsgCount();
+ Subscription subscription = ((SubscriptionAcquiredState)state).getSubscription();
+ if (subscription != null)
+ {
+ subscription.releaseQueueEntry(this);
+ }
}
-
+
if(!getQueue().isDeleted())
{
getQueue().requeue(this);
@@ -311,16 +314,15 @@ public class QueueEntryImpl implements QueueEntry
public Subscription getDeliveredSubscription()
{
- EntryState state = _state;
- if (state instanceof SubscriptionAcquiredState)
- {
- return ((SubscriptionAcquiredState) state).getSubscription();
- }
- else
- {
- return null;
- }
-
+ EntryState state = _state;
+ if (state instanceof SubscriptionAcquiredState)
+ {
+ return ((SubscriptionAcquiredState) state).getSubscription();
+ }
+ else
+ {
+ return null;
+ }
}
public void reject()
@@ -409,50 +411,51 @@ public class QueueEntryImpl implements QueueEntry
public void routeToAlternate()
{
final AMQQueue currentQueue = getQueue();
- Exchange alternateExchange = currentQueue.getAlternateExchange();
+ Exchange alternateExchange = currentQueue.getAlternateExchange();
- if(alternateExchange != null)
+ if (alternateExchange != null)
+ {
+ final List<? extends BaseQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this));
+ final ServerMessage message = getMessage();
+ if (rerouteQueues != null && rerouteQueues.size() != 0)
{
- final List<? extends BaseQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this));
- final ServerMessage message = getMessage();
- if(rerouteQueues != null && rerouteQueues.size() != 0)
- {
- ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
- txn.enqueue(rerouteQueues, message, new ServerTransaction.Action() {
- public void postCommit()
+ ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
+
+ txn.enqueue(rerouteQueues, message, new ServerTransaction.Action()
+ {
+ public void postCommit()
+ {
+ try
{
- try
+ for (BaseQueue queue : rerouteQueues)
{
- for(BaseQueue queue : rerouteQueues)
- {
- queue.enqueue(message);
- }
- }
- catch (AMQException e)
- {
- throw new RuntimeException(e);
+ queue.enqueue(message);
}
}
-
- public void onRollback()
+ catch (AMQException e)
{
-
+ throw new RuntimeException(e);
}
- });
- txn.dequeue(currentQueue,message,
- new ServerTransaction.Action()
- {
- public void postCommit()
- {
- discard();
- }
-
- public void onRollback()
- {
-
- }
- });
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
+ txn.dequeue(currentQueue, message, new ServerTransaction.Action()
+ {
+ public void postCommit()
+ {
+ discard();
+ }
+
+ public void onRollback()
+ {
+
+ }
+ });
}
}
}
@@ -492,33 +495,6 @@ public class QueueEntryImpl implements QueueEntry
return getEntryId() > other.getEntryId() ? 1 : getEntryId() < other.getEntryId() ? -1 : 0;
}
- public QueueEntryImpl getNext()
- {
-
- QueueEntryImpl next = nextNode();
- while(next != null && next.isDispensed() )
- {
-
- final QueueEntryImpl newNext = next.nextNode();
- if(newNext != null)
- {
- SimpleQueueEntryList._nextUpdater.compareAndSet(this,next, newNext);
- next = nextNode();
- }
- else
- {
- next = null;
- }
-
- }
- return next;
- }
-
- QueueEntryImpl nextNode()
- {
- return _next;
- }
-
public boolean isDeleted()
{
return _state == DELETED_STATE;
@@ -530,7 +506,7 @@ public class QueueEntryImpl implements QueueEntry
if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE))
{
- _queueEntryList.advanceHead();
+ _queueEntryList.entryDeleted(this);
return true;
}
else
@@ -554,4 +530,19 @@ public class QueueEntryImpl implements QueueEntry
return _state.isDispensed();
}
+ public int getDeliveryCount()
+ {
+ return _deliveryCount;
+ }
+
+ public void incrementDeliveryCount()
+ {
+ _deliveryCountUpdater.incrementAndGet(this);
+ }
+
+ public void decrementDeliveryCount()
+ {
+ _deliveryCountUpdater.decrementAndGet(this);
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
index c5c115a2d1..73ebb0f300 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryIterator.java
@@ -20,11 +20,11 @@
*/
package org.apache.qpid.server.queue;
-public interface QueueEntryIterator
+public interface QueueEntryIterator<QE extends QueueEntry>
{
boolean atTail();
- QueueEntry getNode();
+ QE getNode();
boolean advance();
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
index b4042ce02c..77c4b912e0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
@@ -22,15 +22,17 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.server.message.ServerMessage;
-public interface QueueEntryList
+public interface QueueEntryList<Q extends QueueEntry>
{
AMQQueue getQueue();
- QueueEntry add(ServerMessage message);
+ Q add(ServerMessage message);
- QueueEntry next(QueueEntry node);
+ Q next(Q node);
- QueueEntryIterator iterator();
+ QueueEntryIterator<Q> iterator();
- QueueEntry getHead();
+ Q getHead();
+
+ void entryDeleted(Q queueEntry);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
index 7e1d57e205..5270f9f740 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
@@ -27,6 +27,11 @@ import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.queue.QueueRunner;
import org.apache.qpid.server.queue.SimpleAMQQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
/**
* QueueRunners are Runnables used to process a queue when requiring
* asynchronous message delivery to subscriptions, which is necessary
@@ -37,33 +42,64 @@ public class QueueRunner implements ReadWriteRunnable
{
private static final Logger _logger = Logger.getLogger(QueueRunner.class);
- private final String _name;
private final SimpleAMQQueue _queue;
- public QueueRunner(SimpleAMQQueue queue, long count)
+ private static int IDLE = 0;
+ private static int SCHEDULED = 1;
+ private static int RUNNING = 2;
+
+
+ private final AtomicInteger _scheduled = new AtomicInteger(IDLE);
+
+ private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+ private final AtomicBoolean _stateChange = new AtomicBoolean();
+
+ private final AtomicLong _lastRunAgain = new AtomicLong();
+ private final AtomicLong _lastRunTime = new AtomicLong();
+
+ private long _runs;
+ private long _continues;
+
+ public QueueRunner(SimpleAMQQueue queue)
{
_queue = queue;
- _name = "QueueRunner-" + count + "-" + queue.getLogActor();
}
+ private int trouble = 0;
+
public void run()
{
- String originalName = Thread.currentThread().getName();
- try
+ if(_scheduled.compareAndSet(SCHEDULED,RUNNING))
{
- Thread.currentThread().setName(_name);
- CurrentActor.set(_queue.getLogActor());
+ long runAgain = Long.MIN_VALUE;
+ _stateChange.set(false);
+ try
+ {
+ CurrentActor.set(_queue.getLogActor());
+
+ runAgain = _queue.processQueue(this);
+ }
+ catch (AMQException e)
+ {
+ _logger.error("Exception during asynchronous delivery by " + toString(), e);
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ _scheduled.compareAndSet(RUNNING, IDLE);
+ long stateChangeCount = _queue.getStateChangeCount();
+ _lastRunAgain.set(runAgain);
+ _lastRunTime.set(System.nanoTime());
+ if(runAgain == 0L || runAgain != stateChangeCount || _stateChange.compareAndSet(true,false))
+ {
+ _continues++;
+ if(_scheduled.compareAndSet(IDLE, SCHEDULED))
+ {
+ _queue.execute(this);
+ }
+ }
- _queue.processQueue(this);
- }
- catch (AMQException e)
- {
- _logger.error("Exception during asynchronous delivery by " + _name, e);
- }
- finally
- {
- CurrentActor.remove();
- Thread.currentThread().setName(originalName);
}
}
@@ -79,6 +115,21 @@ public class QueueRunner implements ReadWriteRunnable
public String toString()
{
- return _name;
+ return "QueueRunner-" + _queue.getLogActor();
}
-} \ No newline at end of file
+
+ public void execute(Executor executor)
+ {
+ _stateChange.set(true);
+ if(_scheduled.compareAndSet(IDLE, SCHEDULED))
+ {
+ executor.execute(this);
+ }
+ }
+
+ public boolean isIdle()
+ {
+ return _scheduled.get() == IDLE;
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index 7effb1c0f8..08dab4e5fc 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -155,11 +155,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private final Set<NotificationCheck> _notificationChecks = EnumSet.noneOf(NotificationCheck.class);
- static final int MAX_ASYNC_DELIVERIES = 10;
+ static final int MAX_ASYNC_DELIVERIES = 80;
private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE);
- private AtomicReference<Runnable> _asynchronousRunner = new AtomicReference<Runnable>(null);
+
private final Executor _asyncDelivery;
private AtomicInteger _deliveredMessages = new AtomicInteger();
private AtomicBoolean _stopped = new AtomicBoolean(false);
@@ -188,6 +188,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private ConfigurationPlugin _queueConfiguration;
private final boolean _isTopic;
+ /** the maximum delivery count for each message on this queue or 0 if maximum delivery count is not to be enforced. */
+ private int _maximumDeliveryCount = ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount();
protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map<String,Object> arguments)
{
@@ -358,6 +360,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_alternateExchange = exchange;
}
+ public void setAlternateExchange(String exchangeName)
+ {
+ if(exchangeName == null || exchangeName.equals(""))
+ {
+ _alternateExchange = null;
+ return;
+ }
+
+ Exchange exchange = getVirtualHost().getExchangeRegistry().getExchange(new AMQShortString(exchangeName));
+ if (exchange == null)
+ {
+ throw new RuntimeException("Exchange '" + exchangeName + "' is not registered with the VirtualHost.");
+ }
+ setAlternateExchange(exchange);
+ }
+
public Map<String, Object> getArguments()
{
return _arguments;
@@ -528,13 +546,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
//Reconfigure the queue for to reflect this new binding.
ConfigurationPlugin config = getVirtualHost().getConfiguration().getQueueConfiguration(this);
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Reconfiguring queue(" + this + ") with config:" + config + " was "+ _queueConfiguration);
- }
-
if (config != null)
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Reconfiguring queue(" + this + ") with config:" + config + " was "+ _queueConfiguration);
+ }
// Reconfigure with new config.
configure(config);
}
@@ -575,40 +592,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException
{
+ incrementTxnEnqueueStats(message);
+ incrementQueueCount();
+ incrementQueueSize(message);
+
_totalMessagesReceived.incrementAndGet();
- Subscription exclusiveSub = _exclusiveSubscriber;
+ final Subscription exclusiveSub = _exclusiveSubscriber;
if(!_isTopic || _subscriptionList.size()!=0)
{
- incrementTxnEnqueueStats(message);
- incrementQueueCount();
- incrementQueueSize(message);
-
- QueueEntry entry;
+ QueueEntry entry = _entries.add(message);
- if (exclusiveSub != null)
+ if(action != null || (exclusiveSub == null && _queueRunner.isIdle()))
{
- exclusiveSub.getSendLock();
-
- try
- {
- entry = _entries.add(message);
-
- deliverToSubscription(exclusiveSub, entry);
- }
- finally
- {
- exclusiveSub.releaseSendLock();
- }
- }
- else
- {
- entry = _entries.add(message);
/*
-
iterate over subscriptions and if any is at the end of the queue and can deliver this message, then deliver the message
-
*/
SubscriptionList.SubscriptionNode node = _subscriptionList.getMarkedNode();
SubscriptionList.SubscriptionNode nextNode = node.findNext();
@@ -654,12 +653,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+
if (entry.isAvailable())
{
checkSubscriptionsNotAheadOfDelivery(entry);
- deliverAsync();
+ if (exclusiveSub != null)
+ {
+ deliverAsync(exclusiveSub);
+ }
+ else
+ {
+ deliverAsync();
+ }
}
if(_managedObject != null)
@@ -678,30 +685,32 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
throws AMQException
{
- sub.getSendLock();
- try
+ if(sub.trySendLock())
{
- if (subscriptionReadyAndHasInterest(sub, entry)
- && !sub.isSuspended())
+ try
{
- if (!sub.wouldSuspend(entry))
+ if (subscriptionReadyAndHasInterest(sub, entry)
+ && !sub.isSuspended())
{
- if (sub.acquires() && !entry.acquire(sub))
+ if (!sub.wouldSuspend(entry))
{
- // restore credit here that would have been taken away by wouldSuspend since we didn't manage
- // to acquire the entry for this subscription
- sub.onDequeue(entry);
- }
- else
- {
- deliverMessage(sub, entry);
+ if (sub.acquires() && !entry.acquire(sub))
+ {
+ // restore credit here that would have been taken away by wouldSuspend since we didn't manage
+ // to acquire the entry for this subscription
+ sub.restoreCredit(entry);
+ }
+ else
+ {
+ deliverMessage(sub, entry, false);
+ }
}
}
}
- }
- finally
- {
- sub.releaseSendLock();
+ finally
+ {
+ sub.releaseSendLock();
+ }
}
}
@@ -745,7 +754,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_byteTxnDequeues.addAndGet(entry.getSize());
}
- private void deliverMessage(final Subscription sub, final QueueEntry entry)
+ private void deliverMessage(final Subscription sub, final QueueEntry entry, boolean batch)
throws AMQException
{
setLastSeenEntry(sub, entry);
@@ -753,7 +762,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_deliveredMessages.incrementAndGet();
incrementUnackedMsgCount();
- sub.send(entry);
+ sub.send(entry, batch);
if(_isTopic)
{
@@ -893,7 +902,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
if (!subscription.isClosed())
{
- deliverMessage(subscription, entry);
+ deliverMessage(subscription, entry, false);
return true;
}
else
@@ -1035,6 +1044,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_exclusiveSubscriber = exclusiveSubscriber;
}
+ long getStateChangeCount()
+ {
+ return _stateChangeCount.get();
+ }
+
+
public static interface QueueEntryFilter
{
public boolean accept(QueueEntry entry);
@@ -1335,7 +1350,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
QueueEntryIterator queueListIterator = _entries.iterator();
long count = 0;
- ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new LocalTransaction(getVirtualHost().getMessageStore());
while (queueListIterator.advance())
{
@@ -1358,7 +1373,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
private void dequeueEntry(final QueueEntry node)
{
- ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getMessageStore());
dequeueEntry(node, txn);
}
@@ -1435,7 +1450,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
});
- ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
+ ServerTransaction txn = new LocalTransaction(getVirtualHost().getMessageStore());
if(_alternateExchange != null)
{
@@ -1604,26 +1619,34 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
+ private QueueRunner _queueRunner = new QueueRunner(this);
public void deliverAsync()
{
- QueueRunner runner = new QueueRunner(this, _stateChangeCount.incrementAndGet());
+ _stateChangeCount.incrementAndGet();
+
+ _queueRunner.execute(_asyncDelivery);
- if (_asynchronousRunner.compareAndSet(null, runner))
- {
- _asyncDelivery.execute(runner);
- }
}
public void deliverAsync(Subscription sub)
{
- SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER);
- if(flusher == null)
+ //_stateChangeCount.incrementAndGet();
+ if(_exclusiveSubscriber == null)
{
- flusher = new SubFlushRunner(sub);
- sub.set(SUB_FLUSH_RUNNER, flusher);
+ deliverAsync();
}
- _asyncDelivery.execute(flusher);
+ else
+ {
+ SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER);
+ if(flusher == null)
+ {
+ flusher = new SubFlushRunner(sub);
+ sub.set(SUB_FLUSH_RUNNER, flusher);
+ }
+ flusher.execute(_asyncDelivery);
+ }
+
}
public void flushSubscription(Subscription sub) throws AMQException
@@ -1639,25 +1662,49 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public boolean flushSubscription(Subscription sub, long iterations) throws AMQException
{
boolean atTail = false;
+ final boolean keepSendLockHeld = iterations <= SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+ boolean queueEmpty = false;
- while (!sub.isSuspended() && !atTail && iterations != 0)
+ try
{
- boolean queueEmpty = false;
- try
+
+ if(keepSendLockHeld)
{
sub.getSendLock();
- atTail = attemptDelivery(sub);
- if (atTail && getNextAvailableEntry(sub) == null)
+ }
+
+ while (!sub.isSuspended() && !atTail && iterations != 0)
+ {
+ try
{
- queueEmpty = true;
+ if(!keepSendLockHeld)
+ {
+ sub.getSendLock();
+ }
+
+ atTail = attemptDelivery(sub, true);
+ if (atTail && getNextAvailableEntry(sub) == null)
+ {
+ queueEmpty = true;
+ }
+ else if (!atTail)
+ {
+ iterations--;
+ }
}
- else if (!atTail)
+ finally
{
- iterations--;
+ if(!keepSendLockHeld)
+ {
+ sub.releaseSendLock();
+ }
}
}
- finally
+ }
+ finally
+ {
+ if(keepSendLockHeld)
{
sub.releaseSendLock();
}
@@ -1665,8 +1712,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
sub.queueEmpty();
}
+ sub.flushBatched();
+
}
+
// if there's (potentially) more than one subscription the others will potentially not have been advanced to the
// next entry they are interested in yet. This would lead to holding on to references to expired messages, etc
// which would give us memory "leak".
@@ -1684,11 +1734,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
*
* Looks up the next node for the subscription and attempts to deliver it.
*
+ *
* @param sub
+ * @param batch
* @return true if we have completed all possible deliveries for this sub.
* @throws AMQException
*/
- private boolean attemptDelivery(Subscription sub) throws AMQException
+ private boolean attemptDelivery(Subscription sub, boolean batch) throws AMQException
{
boolean atTail = false;
@@ -1706,11 +1758,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
if (sub.acquires() && !node.acquire(sub))
{
- sub.onDequeue(node);
+ // restore credit here that would have been taken away by wouldSuspend since we didn't manage
+ // to acquire the entry for this subscription
+ sub.restoreCredit(node);
}
else
{
- deliverMessage(sub, node);
+ deliverMessage(sub, node, batch);
}
}
@@ -1814,23 +1868,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
* @param runner the Runner to schedule
* @throws AMQException
*/
- public void processQueue(QueueRunner runner) throws AMQException
+ public long processQueue(QueueRunner runner) throws AMQException
{
- long stateChangeCount;
+ long stateChangeCount = Long.MIN_VALUE;
long previousStateChangeCount = Long.MIN_VALUE;
+ long rVal = Long.MIN_VALUE;
boolean deliveryIncomplete = true;
boolean lastLoop = false;
int iterations = MAX_ASYNC_DELIVERIES;
- _asynchronousRunner.compareAndSet(runner, null);
+ final int numSubs = _subscriptionList.size();
+
+ final int perSub = Math.max(iterations / Math.max(numSubs,1), 1);
// For every message enqueue/requeue the we fire deliveryAsync() which
// increases _stateChangeCount. If _sCC changes whilst we are in our loop
// (detected by setting previousStateChangeCount to stateChangeCount in the loop body)
// then we will continue to run for a maximum of iterations.
// So whilst delivery/rejection is going on a processQueue thread will be running
- while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete) && _asynchronousRunner.compareAndSet(null, runner))
+ while (iterations != 0 && ((previousStateChangeCount != (stateChangeCount = _stateChangeCount.get())) || deliveryIncomplete))
{
// we want to have one extra loop after every subscription has reached the point where it cannot move
// further, just in case the advance of one subscription in the last loop allows a different subscription to
@@ -1841,6 +1898,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
//further asynchronous delivery is required since the
//previous loop. keep going if iteration slicing allows.
lastLoop = false;
+ rVal = stateChangeCount;
}
previousStateChangeCount = stateChangeCount;
@@ -1853,30 +1911,43 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
Subscription sub = subscriptionIter.getNode().getSubscription();
sub.getSendLock();
- try
- {
- //attempt delivery. returns true if no further delivery currently possible to this sub
- subscriptionDone = attemptDelivery(sub);
- if (subscriptionDone)
+
+ try
{
- if(lastLoop)
+ for(int i = 0 ; i < perSub; i++)
{
- sub.queueEmpty();
+ //attempt delivery. returns true if no further delivery currently possible to this sub
+ subscriptionDone = attemptDelivery(sub, true);
+ if (subscriptionDone)
+ {
+ sub.flushBatched();
+ //close autoClose subscriptions if we are not currently intent on continuing
+ if (lastLoop && !sub.isSuspended() )
+ {
+ sub.queueEmpty();
+ }
+ break;
+ }
+ else
+ {
+ //this subscription can accept additional deliveries, so we must
+ //keep going after this (if iteration slicing allows it)
+ allSubscriptionsDone = false;
+ lastLoop = false;
+ if(--iterations == 0)
+ {
+ sub.flushBatched();
+ break;
+ }
+ }
}
+
+ sub.flushBatched();
}
- else
+ finally
{
- //this subscription can accept additional deliveries, so we must
- //keep going after this (if iteration slicing allows it)
- allSubscriptionsDone = false;
- lastLoop = false;
- iterations--;
+ sub.releaseSendLock();
}
- }
- finally
- {
- sub.releaseSendLock();
- }
}
if(allSubscriptionsDone && lastLoop)
@@ -1902,24 +1973,24 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
deliveryIncomplete = true;
}
- _asynchronousRunner.set(null);
}
// If iterations == 0 then the limiting factor was the time-slicing rather than available messages or credit
// therefore we should schedule this runner again (unless someone beats us to it :-) ).
- if (iterations == 0 && _asynchronousRunner.compareAndSet(null, runner))
+ if (iterations == 0)
{
if (_logger.isDebugEnabled())
{
_logger.debug("Rescheduling runner:" + runner);
}
- _asyncDelivery.execute(runner);
+ return 0L;
}
+ return rVal;
+
}
public void checkMessageStatus() throws AMQException
{
-
QueueEntryIterator queueListIterator = _entries.iterator();
while (queueListIterator.advance())
@@ -2150,6 +2221,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
setMaximumMessageSize(((QueueConfiguration)config).getMaximumMessageSize());
setMaximumMessageCount(((QueueConfiguration)config).getMaximumMessageCount());
setMinimumAlertRepeatGap(((QueueConfiguration)config).getMinimumAlertRepeatGap());
+ setMaximumDeliveryCount(((QueueConfiguration)config).getMaxDeliveryCount());
_capacity = ((QueueConfiguration)config).getCapacity();
_flowResumeCapacity = ((QueueConfiguration)config).getFlowResumeCapacity();
}
@@ -2271,4 +2343,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
return _logActor;
}
+
+ public int getMaximumDeliveryCount()
+ {
+ return _maximumDeliveryCount;
+ }
+
+ public void setMaximumDeliveryCount(final int maximumDeliveryCount)
+ {
+ _maximumDeliveryCount = maximumDeliveryCount;
+ }
+
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java
new file mode 100644
index 0000000000..0707dc045c
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryImpl.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SimpleQueueEntryImpl extends QueueEntryImpl
+{
+ 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.isDispensed())
+ {
+
+ 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/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
index 46baab8c85..0bb5dcc219 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
@@ -1,10 +1,3 @@
-package org.apache.qpid.server.queue;
-
-import org.apache.qpid.server.message.ServerMessage;
-
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import java.util.concurrent.atomic.AtomicLong;
-
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -25,25 +18,31 @@ import java.util.concurrent.atomic.AtomicLong;
* under the License.
*
*/
-public class SimpleQueueEntryList implements QueueEntryList
+package org.apache.qpid.server.queue;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.apache.qpid.server.message.ServerMessage;
+
+public class SimpleQueueEntryList implements QueueEntryList<SimpleQueueEntryImpl>
{
- private final QueueEntryImpl _head;
+ private final SimpleQueueEntryImpl _head;
- private volatile QueueEntryImpl _tail;
+ private volatile SimpleQueueEntryImpl _tail;
- static final AtomicReferenceFieldUpdater<SimpleQueueEntryList, QueueEntryImpl>
+ static final AtomicReferenceFieldUpdater<SimpleQueueEntryList, SimpleQueueEntryImpl>
_tailUpdater =
AtomicReferenceFieldUpdater.newUpdater
- (SimpleQueueEntryList.class, QueueEntryImpl.class, "_tail");
+ (SimpleQueueEntryList.class, SimpleQueueEntryImpl.class, "_tail");
private final AMQQueue _queue;
- static final AtomicReferenceFieldUpdater<QueueEntryImpl, QueueEntryImpl>
+ static final AtomicReferenceFieldUpdater<SimpleQueueEntryImpl, SimpleQueueEntryImpl>
_nextUpdater =
AtomicReferenceFieldUpdater.newUpdater
- (QueueEntryImpl.class, QueueEntryImpl.class, "_next");
+ (SimpleQueueEntryImpl.class, SimpleQueueEntryImpl.class, "_next");
private AtomicLong _scavenges = new AtomicLong(0L);
private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50);
@@ -52,14 +51,14 @@ public class SimpleQueueEntryList implements QueueEntryList
public SimpleQueueEntryList(AMQQueue queue)
{
_queue = queue;
- _head = new QueueEntryImpl(this);
+ _head = new SimpleQueueEntryImpl(this);
_tail = _head;
}
void advanceHead()
{
- QueueEntryImpl next = _head.nextNode();
- QueueEntryImpl newNext = _head.getNext();
+ SimpleQueueEntryImpl next = _head.getNextNode();
+ SimpleQueueEntryImpl newNext = _head.getNextValidEntry();
if (next == newNext)
{
@@ -73,11 +72,11 @@ public class SimpleQueueEntryList implements QueueEntryList
void scavenge()
{
- QueueEntryImpl next = _head.getNext();
+ SimpleQueueEntryImpl next = _head.getNextValidEntry();
while (next != null)
{
- next = next.getNext();
+ next = next.getNextValidEntry();
}
}
@@ -88,13 +87,13 @@ public class SimpleQueueEntryList implements QueueEntryList
}
- public QueueEntry add(ServerMessage message)
+ public SimpleQueueEntryImpl add(ServerMessage message)
{
- QueueEntryImpl node = createQueueEntry(message);
+ SimpleQueueEntryImpl node = createQueueEntry(message);
for (;;)
{
- QueueEntryImpl tail = _tail;
- QueueEntryImpl next = tail.nextNode();
+ SimpleQueueEntryImpl tail = _tail;
+ SimpleQueueEntryImpl next = tail.getNextNode();
if (tail == _tail)
{
if (next == null)
@@ -115,23 +114,22 @@ public class SimpleQueueEntryList implements QueueEntryList
}
}
- protected QueueEntryImpl createQueueEntry(ServerMessage message)
+ protected SimpleQueueEntryImpl createQueueEntry(ServerMessage message)
{
- return new QueueEntryImpl(this, message);
+ return new SimpleQueueEntryImpl(this, message);
}
- public QueueEntry next(QueueEntry node)
+ public SimpleQueueEntryImpl next(SimpleQueueEntryImpl node)
{
- return ((QueueEntryImpl)node).getNext();
+ return node.getNextValidEntry();
}
-
- public static class QueueEntryIteratorImpl implements QueueEntryIterator
+ public static class QueueEntryIteratorImpl implements QueueEntryIterator<SimpleQueueEntryImpl>
{
- private QueueEntryImpl _lastNode;
+ private SimpleQueueEntryImpl _lastNode;
- QueueEntryIteratorImpl(QueueEntryImpl startNode)
+ QueueEntryIteratorImpl(SimpleQueueEntryImpl startNode)
{
_lastNode = startNode;
}
@@ -139,14 +137,12 @@ public class SimpleQueueEntryList implements QueueEntryList
public boolean atTail()
{
- return _lastNode.nextNode() == null;
+ return _lastNode.getNextNode() == null;
}
- public QueueEntry getNode()
+ public SimpleQueueEntryImpl getNode()
{
-
return _lastNode;
-
}
public boolean advance()
@@ -154,10 +150,10 @@ public class SimpleQueueEntryList implements QueueEntryList
if(!atTail())
{
- QueueEntryImpl nextNode = _lastNode.nextNode();
- while(nextNode.isDispensed() && nextNode.nextNode() != null)
+ SimpleQueueEntryImpl nextNode = _lastNode.getNextNode();
+ while(nextNode.isDispensed() && nextNode.getNextNode() != null)
{
- nextNode = nextNode.nextNode();
+ nextNode = nextNode.getNextNode();
}
_lastNode = nextNode;
return true;
@@ -173,21 +169,26 @@ public class SimpleQueueEntryList implements QueueEntryList
}
- public QueueEntryIterator iterator()
+ public QueueEntryIteratorImpl iterator()
{
return new QueueEntryIteratorImpl(_head);
}
- public QueueEntry getHead()
+ public SimpleQueueEntryImpl getHead()
{
return _head;
}
+ public void entryDeleted(SimpleQueueEntryImpl queueEntry)
+ {
+ advanceHead();
+ }
+
static class Factory implements QueueEntryListFactory
{
- public QueueEntryList createQueueEntryList(AMQQueue queue)
+ public SimpleQueueEntryList createQueueEntryList(AMQQueue queue)
{
return new SimpleQueueEntryList(queue);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java
new file mode 100644
index 0000000000..3f02442704
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueue.java
@@ -0,0 +1,30 @@
+package org.apache.qpid.server.queue;
+
+import java.util.Map;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class SortedQueue extends OutOfOrderQueue
+{
+ private String _sortedPropertyName;
+
+ protected SortedQueue(final String name, final boolean durable,
+ final String owner, final boolean autoDelete, final boolean exclusive,
+ final VirtualHost virtualHost, Map<String, Object> arguments, String sortedPropertyName)
+ {
+ super(name, durable, owner, autoDelete, exclusive, virtualHost,
+ new SortedQueueEntryListFactory(sortedPropertyName), arguments);
+ this._sortedPropertyName = sortedPropertyName;
+ }
+
+ public String getSortedPropertyName()
+ {
+ return _sortedPropertyName;
+ }
+
+ public synchronized void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException
+ {
+ super.enqueue(message, action);
+ }
+} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.java
new file mode 100644
index 0000000000..1052adbe67
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryImpl.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 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/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
new file mode 100644
index 0000000000..5f8ab16c06
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
@@ -0,0 +1,665 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.message.ServerMessage;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.server.queue.SortedQueueEntryImpl.Colour;
+import org.apache.qpid.server.store.StoreContext;
+
+/**
+ * A sorted implementation of QueueEntryList.
+ * Uses the red/black tree algorithm specified in "Introduction to Algorithms".
+ * ISBN-10: 0262033844
+ * ISBN-13: 978-0262033848
+ * @see http://en.wikipedia.org/wiki/Red-black_tree
+ */
+public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl>
+{
+ private final SortedQueueEntryImpl _head;
+ private SortedQueueEntryImpl _root;
+ private long _entryId = Long.MIN_VALUE;
+ private final Object _lock = new Object();
+ private final AMQQueue _queue;
+ private final String _propertyName;
+
+ public SortedQueueEntryList(final AMQQueue queue, final String propertyName)
+ {
+ _queue = queue;
+ _head = new SortedQueueEntryImpl(this);
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public AMQQueue getQueue()
+ {
+ return _queue;
+ }
+
+ @Override
+ public SortedQueueEntryImpl add(final ServerMessage message)
+ {
+ synchronized(_lock)
+ {
+ String key = null;
+ final Object val = message.getMessageHeader().getHeader(_propertyName);
+ if(val != null)
+ {
+ key = val.toString();
+ }
+
+ final SortedQueueEntryImpl entry = new SortedQueueEntryImpl(this,message, ++_entryId);
+ entry.setKey(key);
+
+ insert(entry);
+
+ return entry;
+ }
+ }
+
+ /**
+ * Red Black Tree insert implementation.
+ * @param entry the entry to insert.
+ */
+ private void insert(final SortedQueueEntryImpl entry)
+ {
+ SortedQueueEntryImpl node = _root;
+ if((node = _root) == null)
+ {
+ _root = entry;
+ _head.setNext(entry);
+ entry.setPrev(_head);
+ return;
+ }
+ else
+ {
+ SortedQueueEntryImpl parent = null;
+ while(node != null)
+ {
+ parent = node;
+ if(entry.compareTo(node) < 0)
+ {
+ node = node.getLeft();
+ }
+ else
+ {
+ node = node.getRight();
+ }
+ }
+ entry.setParent(parent);
+
+ if(entry.compareTo(parent) < 0)
+ {
+ parent.setLeft(entry);
+ final SortedQueueEntryImpl prev = parent.getPrev();
+ entry.setNext(parent);
+ prev.setNext(entry);
+ entry.setPrev(prev);
+ parent.setPrev(entry);
+ }
+ else
+ {
+ parent.setRight(entry);
+
+ final SortedQueueEntryImpl next = parent.getNextValidEntry();
+ entry.setNext(next);
+ parent.setNext(entry);
+
+ if(next != null)
+ {
+ next.setPrev(entry);
+ }
+ entry.setPrev(parent);
+ }
+ }
+ entry.setColour(Colour.RED);
+ insertFixup(entry);
+ }
+
+ private void insertFixup(SortedQueueEntryImpl entry)
+ {
+ while(isParentColour(entry, Colour.RED))
+ {
+ final SortedQueueEntryImpl grandparent = nodeGrandparent(entry);
+
+ if(nodeParent(entry) == leftChild(grandparent))
+ {
+ final SortedQueueEntryImpl y = rightChild(grandparent);
+ if(isNodeColour(y, Colour.RED))
+ {
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(y, Colour.BLACK);
+ setColour(grandparent, Colour.RED);
+ entry = grandparent;
+ }
+ else
+ {
+ if(entry == rightChild(nodeParent(entry)))
+ {
+ entry = nodeParent(entry);
+ leftRotate(entry);
+ }
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(nodeGrandparent(entry), Colour.RED);
+ rightRotate(nodeGrandparent(entry));
+ }
+ }
+ else
+ {
+ final SortedQueueEntryImpl y = leftChild(grandparent);
+ if(isNodeColour(y, Colour.RED))
+ {
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(y, Colour.BLACK);
+ setColour(grandparent, Colour.RED);
+ entry = grandparent;
+ }
+ else
+ {
+ if(entry == leftChild(nodeParent(entry)))
+ {
+ entry = nodeParent(entry);
+ rightRotate(entry);
+ }
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(nodeGrandparent(entry), Colour.RED);
+ leftRotate(nodeGrandparent(entry));
+ }
+ }
+ }
+ _root.setColour(Colour.BLACK);
+ }
+
+ private void leftRotate(final SortedQueueEntryImpl entry)
+ {
+ if(entry != null)
+ {
+ final SortedQueueEntryImpl rightChild = rightChild(entry);
+ entry.setRight(rightChild.getLeft());
+ if(entry.getRight() != null)
+ {
+ entry.getRight().setParent(entry);
+ }
+ rightChild.setParent(entry.getParent());
+ if(entry.getParent() == null)
+ {
+ _root = rightChild;
+ }
+ else if(entry == entry.getParent().getLeft())
+ {
+ entry.getParent().setLeft(rightChild);
+ }
+ else
+ {
+ entry.getParent().setRight(rightChild);
+ }
+ rightChild.setLeft(entry);
+ entry.setParent(rightChild);
+ }
+ }
+
+ private void rightRotate(final SortedQueueEntryImpl entry)
+ {
+ if(entry != null)
+ {
+ final SortedQueueEntryImpl leftChild = leftChild(entry);
+ entry.setLeft(leftChild.getRight());
+ if(entry.getLeft() != null)
+ {
+ leftChild.getRight().setParent(entry);
+ }
+ leftChild.setParent(entry.getParent());
+ if(leftChild.getParent() == null)
+ {
+ _root = leftChild;
+ }
+ else if(entry == entry.getParent().getRight())
+ {
+ entry.getParent().setRight(leftChild);
+ }
+ else
+ {
+ entry.getParent().setLeft(leftChild);
+ }
+ leftChild.setRight(entry);
+ entry.setParent(leftChild);
+ }
+ }
+
+ private void setColour(final SortedQueueEntryImpl node, final Colour colour)
+ {
+ if(node != null)
+ {
+ node.setColour(colour);
+ }
+ }
+
+ private SortedQueueEntryImpl leftChild(final SortedQueueEntryImpl node)
+ {
+ return node == null ? null : node.getLeft();
+ }
+
+ private SortedQueueEntryImpl rightChild(final SortedQueueEntryImpl node)
+ {
+ return node == null ? null : node.getRight();
+ }
+
+ private SortedQueueEntryImpl nodeParent(final SortedQueueEntryImpl node)
+ {
+ return node == null ? null : node.getParent();
+ }
+
+ private SortedQueueEntryImpl nodeGrandparent(final SortedQueueEntryImpl node)
+ {
+ return nodeParent(nodeParent(node));
+ }
+
+ private boolean isParentColour(final SortedQueueEntryImpl node, final SortedQueueEntryImpl.Colour colour)
+ {
+
+ return node != null && isNodeColour(node.getParent(), colour);
+ }
+
+ protected boolean isNodeColour(final SortedQueueEntryImpl node, final SortedQueueEntryImpl.Colour colour)
+ {
+ return (node == null ? Colour.BLACK : node.getColour()) == colour;
+ }
+
+ @Override
+ public SortedQueueEntryImpl next(final SortedQueueEntryImpl node)
+ {
+ synchronized(_lock)
+ {
+ if(node.isDispensed() && _head != node)
+ {
+ SortedQueueEntryImpl current = _head;
+ SortedQueueEntryImpl next;
+ while(current != null)
+ {
+ next = current.getNextValidEntry();
+ if(current.compareTo(node)>0 && !current.isDispensed())
+ {
+ break;
+ }
+ else
+ {
+ current = next;
+ }
+ }
+ return current;
+ }
+ else
+ {
+ return node.getNextValidEntry();
+ }
+ }
+ }
+
+ @Override
+ public QueueEntryIterator<SortedQueueEntryImpl> iterator()
+ {
+ return new QueueEntryIteratorImpl(_head);
+ }
+
+ @Override
+ public SortedQueueEntryImpl getHead()
+ {
+ return _head;
+ }
+
+ protected SortedQueueEntryImpl getRoot()
+ {
+ return _root;
+ }
+
+ @Override
+ public void entryDeleted(final SortedQueueEntryImpl entry)
+ {
+ synchronized(_lock)
+ {
+ // If the node to be removed has two children, we swap the position
+ // of the node and its successor in the tree
+ if(leftChild(entry) != null && rightChild(entry) != null)
+ {
+ swapWithSuccessor(entry);
+ }
+
+ // Then deal with the easy doubly linked list deletion (need to do
+ // this after the swap as the swap uses next
+ final SortedQueueEntryImpl prev = entry.getPrev();
+ if(prev != null)
+ {
+ prev.setNext(entry.getNextValidEntry());
+ }
+
+ final SortedQueueEntryImpl next = entry.getNextValidEntry();
+ if(next != null)
+ {
+ next.setPrev(prev);
+ }
+
+ // now deal with splicing
+ final SortedQueueEntryImpl chosenChild;
+
+ if(leftChild(entry) != null)
+ {
+ chosenChild = leftChild(entry);
+ }
+ else
+ {
+ chosenChild = rightChild(entry);
+ }
+
+ if(chosenChild != null)
+ {
+ // we have one child (x), we can move it up to replace x;
+ chosenChild.setParent(entry.getParent());
+ if(chosenChild.getParent() == null)
+ {
+ _root = chosenChild;
+ }
+ else if(entry == entry.getParent().getLeft())
+ {
+ entry.getParent().setLeft(chosenChild);
+ }
+ else
+ {
+ entry.getParent().setRight(chosenChild);
+ }
+
+ entry.setLeft(null);
+ entry.setRight(null);
+ entry.setParent(null);
+
+ if(entry.getColour() == Colour.BLACK)
+ {
+ deleteFixup(chosenChild);
+ }
+
+ }
+ else
+ {
+ // no children
+ if(entry.getParent() == null)
+ {
+ // no parent either - the tree is empty
+ _root = null;
+ }
+ else
+ {
+ if(entry.getColour() == Colour.BLACK)
+ {
+ deleteFixup(entry);
+ }
+
+ if(entry.getParent() != null)
+ {
+ if(entry.getParent().getLeft() == entry)
+ {
+ entry.getParent().setLeft(null);
+ }
+ else if(entry.getParent().getRight() == entry)
+ {
+ entry.getParent().setRight(null);
+ }
+ entry.setParent(null);
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Swaps the position of the node in the tree with it's successor
+ * (that is the node with the next highest key)
+ * @param entry
+ */
+ private void swapWithSuccessor(final SortedQueueEntryImpl entry)
+ {
+ final SortedQueueEntryImpl next = entry.getNextValidEntry();
+ final SortedQueueEntryImpl nextParent = next.getParent();
+ final SortedQueueEntryImpl nextLeft = next.getLeft();
+ final SortedQueueEntryImpl nextRight = next.getRight();
+ final Colour nextColour = next.getColour();
+
+ // Special case - the successor is the right child of the node
+ if(next == entry.getRight())
+ {
+ next.setParent(entry.getParent());
+ if(next.getParent() == null)
+ {
+ _root = next;
+ }
+ else if(next.getParent().getLeft() == entry)
+ {
+ next.getParent().setLeft(next);
+ }
+ else
+ {
+ next.getParent().setRight(next);
+ }
+
+ next.setRight(entry);
+ entry.setParent(next);
+ next.setLeft(entry.getLeft());
+
+ if(next.getLeft() != null)
+ {
+ next.getLeft().setParent(next);
+ }
+
+ next.setColour(entry.getColour());
+ entry.setColour(nextColour);
+ entry.setLeft(nextLeft);
+
+ if(nextLeft != null)
+ {
+ nextLeft.setParent(entry);
+ }
+ entry.setRight(nextRight);
+ if(nextRight != null)
+ {
+ nextRight.setParent(entry);
+ }
+ }
+ else
+ {
+ next.setParent(entry.getParent());
+ if(next.getParent() == null)
+ {
+ _root = next;
+ }
+ else if(next.getParent().getLeft() == entry)
+ {
+ next.getParent().setLeft(next);
+ }
+ else
+ {
+ next.getParent().setRight(next);
+ }
+
+ next.setLeft(entry.getLeft());
+ if(next.getLeft() != null)
+ {
+ next.getLeft().setParent(next);
+ }
+ next.setRight(entry.getRight());
+ if(next.getRight() != null)
+ {
+ next.getRight().setParent(next);
+ }
+ next.setColour(entry.getColour());
+
+ entry.setParent(nextParent);
+ if(nextParent.getLeft() == next)
+ {
+ nextParent.setLeft(entry);
+ }
+ else
+ {
+ nextParent.setRight(entry);
+ }
+
+ entry.setLeft(nextLeft);
+ if(nextLeft != null)
+ {
+ nextLeft.setParent(entry);
+ }
+ entry.setRight(nextRight);
+ if(nextRight != null)
+ {
+ nextRight.setParent(entry);
+ }
+ entry.setColour(nextColour);
+ }
+ }
+
+ private void deleteFixup(SortedQueueEntryImpl entry)
+ {
+ int i = 0;
+ while(entry != null && entry != _root
+ && isNodeColour(entry, Colour.BLACK))
+ {
+ i++;
+
+ if(i > 1000)
+ {
+ return;
+ }
+
+ if(entry == leftChild(nodeParent(entry)))
+ {
+ SortedQueueEntryImpl rightSibling = rightChild(nodeParent(entry));
+ if(isNodeColour(rightSibling, Colour.RED))
+ {
+ setColour(rightSibling, Colour.BLACK);
+ nodeParent(entry).setColour(Colour.RED);
+ leftRotate(nodeParent(entry));
+ rightSibling = rightChild(nodeParent(entry));
+ }
+
+ if(isNodeColour(leftChild(rightSibling), Colour.BLACK)
+ && isNodeColour(rightChild(rightSibling), Colour.BLACK))
+ {
+ setColour(rightSibling, Colour.RED);
+ entry = nodeParent(entry);
+ }
+ else
+ {
+ if(isNodeColour(rightChild(rightSibling), Colour.BLACK))
+ {
+ setColour(leftChild(rightSibling), Colour.BLACK);
+ rightSibling.setColour(Colour.RED);
+ rightRotate(rightSibling);
+ rightSibling = rightChild(nodeParent(entry));
+ }
+ setColour(rightSibling, getColour(nodeParent(entry)));
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(rightChild(rightSibling), Colour.BLACK);
+ leftRotate(nodeParent(entry));
+ entry = _root;
+ }
+ }
+ else
+ {
+ SortedQueueEntryImpl leftSibling = leftChild(nodeParent(entry));
+ if(isNodeColour(leftSibling, Colour.RED))
+ {
+ setColour(leftSibling, Colour.BLACK);
+ nodeParent(entry).setColour(Colour.RED);
+ rightRotate(nodeParent(entry));
+ leftSibling = leftChild(nodeParent(entry));
+ }
+
+ if(isNodeColour(leftChild(leftSibling), Colour.BLACK)
+ && isNodeColour(rightChild(leftSibling), Colour.BLACK))
+ {
+ setColour(leftSibling, Colour.RED);
+ entry = nodeParent(entry);
+ }
+ else
+ {
+ if(isNodeColour(leftChild(leftSibling), Colour.BLACK))
+ {
+ setColour(rightChild(leftSibling), Colour.BLACK);
+ leftSibling.setColour(Colour.RED);
+ leftRotate(leftSibling);
+ leftSibling = leftChild(nodeParent(entry));
+ }
+ setColour(leftSibling, getColour(nodeParent(entry)));
+ setColour(nodeParent(entry), Colour.BLACK);
+ setColour(leftChild(leftSibling), Colour.BLACK);
+ rightRotate(nodeParent(entry));
+ entry = _root;
+ }
+ }
+ }
+ setColour(entry, Colour.BLACK);
+ }
+
+ private Colour getColour(final SortedQueueEntryImpl x)
+ {
+ return x == null ? null : x.getColour();
+ }
+
+ public class QueueEntryIteratorImpl implements QueueEntryIterator<SortedQueueEntryImpl>
+ {
+ private SortedQueueEntryImpl _lastNode;
+
+ public QueueEntryIteratorImpl(final SortedQueueEntryImpl startNode)
+ {
+ _lastNode = startNode;
+ }
+
+ public boolean atTail()
+ {
+ return next(_lastNode) == null;
+ }
+
+ public SortedQueueEntryImpl getNode()
+ {
+ return _lastNode;
+ }
+
+ public boolean advance()
+ {
+ if(!atTail())
+ {
+ SortedQueueEntryImpl nextNode = next(_lastNode);
+ while(nextNode.isDispensed() && next(nextNode) != null)
+ {
+ nextNode = next(nextNode);
+ }
+ _lastNode = nextNode;
+ return true;
+
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java
new file mode 100644
index 0000000000..7a70795e77
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryListFactory.java
@@ -0,0 +1,19 @@
+package org.apache.qpid.server.queue;
+
+public class SortedQueueEntryListFactory implements QueueEntryListFactory
+{
+
+ private final String _propertyName;
+
+ public SortedQueueEntryListFactory(final String propertyName)
+ {
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public QueueEntryList<SortedQueueEntryImpl> createQueueEntryList(final AMQQueue queue)
+ {
+ return new SortedQueueEntryList(queue, _propertyName);
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
index 46c1a6af9a..fbef23dca1 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
@@ -27,6 +27,10 @@ import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.AMQException;
import org.apache.log4j.Logger;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
class SubFlushRunner implements ReadWriteRunnable
{
@@ -34,29 +38,33 @@ class SubFlushRunner implements ReadWriteRunnable
private final Subscription _sub;
- private final String _name;
+
+ private static int IDLE = 0;
+ private static int SCHEDULED = 1;
+ private static int RUNNING = 2;
+
+
+ private final AtomicInteger _scheduled = new AtomicInteger(IDLE);
+
+
private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
+ private final AtomicBoolean _stateChange = new AtomicBoolean();
public SubFlushRunner(Subscription sub)
{
_sub = sub;
- _name = "SubFlushRunner-"+_sub;
}
public void run()
{
-
- String originalName = Thread.currentThread().getName();
- try
+ if(_scheduled.compareAndSet(SCHEDULED, RUNNING))
{
- Thread.currentThread().setName(_name);
-
boolean complete = false;
+ _stateChange.set(false);
try
{
CurrentActor.set(_sub.getLogActor());
complete = getQueue().flushSubscription(_sub, ITERATIONS);
-
}
catch (AMQException e)
{
@@ -66,17 +74,15 @@ class SubFlushRunner implements ReadWriteRunnable
{
CurrentActor.remove();
}
- if (!complete && !_sub.isSuspended())
+ _scheduled.compareAndSet(RUNNING, IDLE);
+ if ((!complete || _stateChange.compareAndSet(true,false))&& !_sub.isSuspended())
{
- getQueue().execute(this);
+ if(_scheduled.compareAndSet(IDLE,SCHEDULED))
+ {
+ getQueue().execute(this);
+ }
}
-
}
- finally
- {
- Thread.currentThread().setName(originalName);
- }
-
}
private SimpleAMQQueue getQueue()
@@ -93,4 +99,18 @@ class SubFlushRunner implements ReadWriteRunnable
{
return true;
}
+
+ public String toString()
+ {
+ return "SubFlushRunner-" + _sub.getLogActor();
+ }
+
+ public void execute(Executor executor)
+ {
+ _stateChange.set(true);
+ if(_scheduled.compareAndSet(IDLE,SCHEDULED))
+ {
+ executor.execute(this);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index c07074f69c..7eb1b54693 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -250,14 +250,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
try
{
+ initialiseManagedObjectRegistry();
+
configure();
_qmfService = new QMFService(getConfigStore(), this);
CurrentActor.get().message(BrokerMessages.STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion()));
- initialiseManagedObjectRegistry();
-
_virtualHostRegistry = new VirtualHostRegistry(this);
_securityManager = new SecurityManager(_configuration, _pluginManager);
@@ -471,12 +471,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
close(_authenticationManager);
- close(_managedObjectRegistry);
-
close(_qmfService);
close(_pluginManager);
+ close(_managedObjectRegistry);
+
CurrentActor.get().message(BrokerMessages.STOPPED());
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
index 8b5ff6781d..ec11e2d39c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
@@ -73,11 +73,6 @@ public abstract class AbstractProxyPlugin extends AbstractPlugin
return getDefault();
}
- public Result authoriseExecute(ObjectType object, ObjectProperties properties)
- {
- return getDefault();
- }
-
public Result authoriseUpdate(ObjectType object, ObjectProperties properties)
{
return getDefault();
@@ -121,8 +116,6 @@ public abstract class AbstractProxyPlugin extends AbstractPlugin
return authoriseDelete(objectType, properties);
case PURGE:
return authorisePurge(objectType, properties);
- case EXECUTE:
- return authoriseExecute(objectType, properties);
case UPDATE:
return authoriseUpdate(objectType, properties);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
index f582fed6a0..abf9e3379d 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
@@ -20,10 +20,8 @@ package org.apache.qpid.server.security;
import static org.apache.qpid.server.security.access.ObjectType.EXCHANGE;
import static org.apache.qpid.server.security.access.ObjectType.METHOD;
-import static org.apache.qpid.server.security.access.ObjectType.OBJECT;
import static org.apache.qpid.server.security.access.ObjectType.QUEUE;
import static org.apache.qpid.server.security.access.ObjectType.VIRTUALHOST;
-import static org.apache.qpid.server.security.access.Operation.ACCESS;
import static org.apache.qpid.server.security.access.Operation.BIND;
import static org.apache.qpid.server.security.access.Operation.CONSUME;
import static org.apache.qpid.server.security.access.Operation.CREATE;
@@ -67,7 +65,14 @@ public class SecurityManager
/** Container for the {@link Principal} that is using to this thread. */
private static final ThreadLocal<Subject> _subject = new ThreadLocal<Subject>();
-
+ private static final ThreadLocal<Boolean> _accessChecksDisabled = new ThreadLocal<Boolean>()
+ {
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ };
+
private PluginManager _pluginManager;
private Map<String, SecurityPluginFactory> _pluginFactories = new HashMap<String, SecurityPluginFactory>();
private Map<String, SecurityPlugin> _globalPlugins = new HashMap<String, SecurityPlugin>();
@@ -194,6 +199,11 @@ public class SecurityManager
private boolean checkAllPlugins(AccessCheck checker)
{
+ if(_accessChecksDisabled.get())
+ {
+ return true;
+ }
+
HashMap<String, SecurityPlugin> remainingPlugins = new HashMap<String, SecurityPlugin>(_globalPlugins);
for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet())
@@ -273,21 +283,6 @@ public class SecurityManager
}
});
}
-
- // TODO not implemented yet, awaiting consensus
- public boolean authoriseObject(final String packageName, final String className)
- {
- return checkAllPlugins(new AccessCheck()
- {
- Result allowed(SecurityPlugin plugin)
- {
- ObjectProperties properties = new ObjectProperties();
- properties.put(ObjectProperties.Property.PACKAGE, packageName);
- properties.put(ObjectProperties.Property.CLASS, className);
- return plugin.authorise(ACCESS, OBJECT, properties);
- }
- });
- }
public boolean authoriseMethod(final Operation operation, final String componentName, final String methodName)
{
@@ -329,17 +324,6 @@ public class SecurityManager
});
}
- public boolean authoriseConsume(final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
- Result allowed(SecurityPlugin plugin)
- {
- return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(exclusive, noAck, noLocal, nowait, queue));
- }
- });
- }
-
public boolean authoriseCreateExchange(final Boolean autoDelete, final Boolean durable, final AMQShortString exchangeName,
final Boolean internal, final Boolean nowait, final Boolean passive, final AMQShortString exchangeType)
{
@@ -419,4 +403,14 @@ public class SecurityManager
}
});
}
+
+ public static boolean setAccessChecksDisabled(final boolean status)
+ {
+ //remember current value
+ boolean current = _accessChecksDisabled.get();
+
+ _accessChecksDisabled.set(status);
+
+ return current;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
index 7103b30283..69c7ff185a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
@@ -32,14 +32,12 @@ import java.util.Set;
public enum ObjectType
{
ALL(Operation.ALL),
- VIRTUALHOST(ACCESS),
- QUEUE(CREATE, DELETE, PURGE, CONSUME),
- TOPIC(CREATE, DELETE, PURGE, CONSUME),
- EXCHANGE(ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
+ VIRTUALHOST(Operation.ALL, ACCESS),
+ QUEUE(Operation.ALL, CREATE, DELETE, PURGE, CONSUME),
+ EXCHANGE(Operation.ALL, ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
LINK, // Not allowed in the Java broker
ROUTE, // Not allowed in the Java broker
- METHOD(Operation.ALL, ACCESS, UPDATE, EXECUTE),
- OBJECT(ACCESS);
+ METHOD(Operation.ALL, ACCESS, UPDATE);
private EnumSet<Operation> _actions;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
index 06d7f8fd0c..21ea042eed 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
@@ -32,8 +32,7 @@ public enum Operation
UNBIND,
DELETE,
PURGE,
- UPDATE,
- EXECUTE;
+ UPDATE;
public static Operation parse(String text)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
index 1612d13b1b..7cb34da804 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
@@ -384,16 +384,8 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
BufferedReader reader = null;
PrintStream writer = null;
-
- Random r = new Random();
- File tmp;
- do
- {
- tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp");
- }
- while(tmp.exists());
-
- tmp.deleteOnExit();
+
+ final File tmp = createTempFileOnSameFilesystem(_passwordFile);
try
{
@@ -458,52 +450,72 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
}
finally
{
- if (reader != null)
- {
- reader.close();
- }
-
if (writer != null)
{
writer.close();
}
- }
-
- // Swap temp file to main password file.
- File old = new File(_passwordFile.getAbsoluteFile() + ".old");
- if (old.exists())
- {
- old.delete();
- }
-
- if(!_passwordFile.renameTo(old))
- {
- //unable to rename the existing file to the backup name
- _logger.error("Could not backup the existing password file");
- throw new IOException("Could not backup the existing password file");
- }
-
- if(!tmp.renameTo(_passwordFile))
- {
- //failed to rename the new file to the required filename
-
- if(!old.renameTo(_passwordFile))
+ if (reader != null)
{
- //unable to return the backup to required filename
- _logger.error("Could not rename the new password file into place, and unable to restore original file");
- throw new IOException("Could not rename the new password file into place, and unable to restore original file");
+ reader.close();
}
-
- _logger.error("Could not rename the new password file into place");
- throw new IOException("Could not rename the new password file into place");
}
-
+
+ swapTempFileToLive(_passwordFile, tmp);
+
}
finally
{
_userUpdate.unlock();
}
}
+
+ private void swapTempFileToLive(final File live, final File temp) throws IOException
+ {
+ // Remove any existing ".old" file
+ final File old = new File(live.getAbsoluteFile() + ".old");
+ if (old.exists())
+ {
+ old.delete();
+ }
+
+ // Create an new ".old" file
+ if(!live.renameTo(old))
+ {
+ //unable to rename the existing file to the backup name
+ _logger.error("Could not backup the existing password file");
+ throw new IOException("Could not backup the existing password file");
+ }
+
+ // Move temp file to be the new "live" file
+ if(!temp.renameTo(live))
+ {
+ //failed to rename the new file to the required filename
+ if(!old.renameTo(live))
+ {
+ //unable to return the backup to required filename
+ _logger.error("Could not rename the new password file into place, and unable to restore original file");
+ throw new IOException("Could not rename the new password file into place, and unable to restore original file");
+ }
+
+ _logger.error("Could not rename the new password file into place");
+ throw new IOException("Could not rename the new password file into place");
+ }
+ }
+
+ private File createTempFileOnSameFilesystem(final File liveFile)
+ {
+ File tmp;
+ final Random r = new Random();
+
+ do
+ {
+ tmp = new File(liveFile.getPath() + r.nextInt() + ".tmp");
+ }
+ while(tmp.exists());
+
+ tmp.deleteOnExit();
+ return tmp;
+ }
public void reload() throws IOException
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
index 8b099b62ce..d3f46d2e90 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
@@ -142,6 +142,19 @@ public class DerbyMessageStore implements MessageStore
private boolean _configured;
+ private static final class CommitStoreFuture implements StoreFuture
+ {
+ public boolean isComplete()
+ {
+ return true;
+ }
+
+ public void waitForCompletion()
+ {
+
+ }
+ }
+
private enum State
{
INITIAL,
@@ -910,19 +923,19 @@ public class DerbyMessageStore implements MessageStore
throws AMQStoreException
{
Connection conn = null;
+ PreparedStatement stmt = null;
try
{
conn = newAutoCommitConnection();
// exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255), arguments blob
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_BINDINGS);
+ stmt = conn.prepareStatement(DELETE_FROM_BINDINGS);
stmt.setString(1, exchange.getNameShortString().toString() );
stmt.setString(2, queue.getNameShortString().toString());
stmt.setString(3, routingKey == null ? null : routingKey.toString());
-
+
int result = stmt.executeUpdate();
- stmt.close();
-
+
if(result != 1)
{
throw new AMQStoreException("Queue binding for queue with name " + queue.getNameShortString() + " to exchange "
@@ -936,21 +949,9 @@ public class DerbyMessageStore implements MessageStore
}
finally
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e)
- {
- _logger.error(e);
- }
- }
-
+ closePreparedStatement(stmt);
+ closeConnection(conn);
}
-
-
}
public void createQueue(AMQQueue queue) throws AMQStoreException
@@ -1153,15 +1154,14 @@ public class DerbyMessageStore implements MessageStore
AMQShortString name = queue.getNameShortString();
_logger.debug("public void removeQueue(AMQShortString name = " + name + "): called");
Connection conn = null;
-
+ PreparedStatement stmt = null;
try
{
conn = newAutoCommitConnection();
- PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE);
+ stmt = conn.prepareStatement(DELETE_FROM_QUEUE);
stmt.setString(1, name.toString());
int results = stmt.executeUpdate();
- stmt.close();
-
+
if (results == 0)
{
throw new AMQStoreException("Queue " + name + " not found");
@@ -1173,18 +1173,8 @@ public class DerbyMessageStore implements MessageStore
}
finally
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e)
- {
- _logger.error(e);
- }
- }
-
+ closePreparedStatement(stmt);
+ closeConnection(conn);
}
@@ -1317,19 +1307,7 @@ public class DerbyMessageStore implements MessageStore
public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQStoreException
{
commitTran(connWrapper);
- return new StoreFuture()
- {
- public boolean isComplete()
- {
- return true;
- }
-
- public void waitForCompletion()
- {
-
- }
- };
-
+ return new CommitStoreFuture();
}
public void abortTran(ConnectionWrapper connWrapper) throws AMQStoreException
@@ -1572,6 +1550,7 @@ public class DerbyMessageStore implements MessageStore
{
_logger.debug("Adding content chunk offset " + offset + " for message " +messageId);
}
+ PreparedStatement stmt = null;
try
{
@@ -1580,7 +1559,7 @@ public class DerbyMessageStore implements MessageStore
byte[] chunkData = new byte[src.limit()];
src.duplicate().get(chunkData);
- PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
+ stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT);
stmt.setLong(1,messageId);
stmt.setInt(2, offset);
stmt.setInt(3, offset+chunkData.length);
@@ -1594,24 +1573,16 @@ public class DerbyMessageStore implements MessageStore
ByteArrayInputStream bis = new ByteArrayInputStream(chunkData);
stmt.setBinaryStream(4, bis, chunkData.length);
stmt.executeUpdate();
- stmt.close();
}
catch (SQLException e)
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e1)
- {
-
- }
- }
-
+ closeConnection(conn);
throw new RuntimeException("Error adding content chunk offset " + offset + " for message " + messageId + ": " + e.getMessage(), e);
}
+ finally
+ {
+ closePreparedStatement(stmt);
+ }
}
@@ -1619,13 +1590,13 @@ public class DerbyMessageStore implements MessageStore
public int getContent(long messageId, int offset, ByteBuffer dst)
{
Connection conn = null;
-
+ PreparedStatement stmt = null;
try
{
conn = newAutoCommitConnection();
- PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
+ stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT);
stmt.setLong(1,messageId);
stmt.setInt(2, offset);
stmt.setInt(3, offset+dst.remaining());
@@ -1656,28 +1627,18 @@ public class DerbyMessageStore implements MessageStore
}
}
- stmt.close();
- conn.close();
return written;
}
catch (SQLException e)
{
- if(conn != null)
- {
- try
- {
- conn.close();
- }
- catch (SQLException e1)
- {
-
- }
- }
-
throw new RuntimeException("Error retrieving content from offset " + offset + " for message " + messageId + ": " + e.getMessage(), e);
}
-
+ finally
+ {
+ closePreparedStatement(stmt);
+ closeConnection(conn);
+ }
}
@@ -1849,5 +1810,33 @@ public class DerbyMessageStore implements MessageStore
}
}
+ private void closeConnection(final Connection conn)
+ {
+ if(conn != null)
+ {
+ try
+ {
+ conn.close();
+ }
+ catch (SQLException e)
+ {
+ _logger.error("Problem closing connection", e);
+ }
+ }
+ }
+ private void closePreparedStatement(final PreparedStatement stmt)
+ {
+ if (stmt != null)
+ {
+ try
+ {
+ stmt.close();
+ }
+ catch(SQLException e)
+ {
+ _logger.error("Problem closing prepared statement", e);
+ }
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
index b49b12fb79..80c5e2866c 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java
@@ -53,12 +53,12 @@ class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDi
}
- public void onRelease()
+ public void onRelease(boolean setRedelivered)
{
final Subscription_0_10 subscription = getSubscription();
if(subscription != null && _entry.isAcquiredBy(_sub))
{
- subscription.release(_entry);
+ subscription.release(_entry, setRedelivered);
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
index b5bb2014b5..a61b0b4e82 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java
@@ -43,11 +43,11 @@ class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDi
_logger.warn("MessageAccept received for message which is using NONE as the accept mode (likely client error)");
}
- public void onRelease()
+ public void onRelease(boolean setRedelivered)
{
if(_entry.isAcquiredBy(_sub))
{
- getSubscription().release(_entry);
+ getSubscription().release(_entry, setRedelivered);
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
index 5c4e413989..bc1be90531 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java
@@ -69,17 +69,24 @@ public interface Subscription
void close();
- void send(QueueEntry msg) throws AMQException;
+ void send(QueueEntry entry, boolean batch) throws AMQException;
+
+ void flushBatched();
void queueDeleted(AMQQueue queue);
boolean wouldSuspend(QueueEntry msg);
+ boolean trySendLock();
+
+
void getSendLock();
void releaseSendLock();
+ void releaseQueueEntry(final QueueEntry queueEntryImpl);
+
void onDequeue(final QueueEntry queueEntry);
void restoreCredit(final QueueEntry queueEntry);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
index adb0a84151..23ae14eef1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java
@@ -119,11 +119,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* This method can be called by each of the publisher threads. As a result all changes to the channel object must be
* thread safe.
*
- * @param msg The message to send
+ *
+ * @param entry
+ * @param batch
* @throws AMQException
*/
@Override
- public void send(QueueEntry msg) throws AMQException
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
// We don't decrement the reference here as we don't want to consume the message
// but we do want to send it to the client.
@@ -131,7 +133,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
synchronized (getChannel())
{
long deliveryTag = getChannel().getNextDeliveryTag();
- sendToClient(msg, deliveryTag);
+ sendToClient(entry, deliveryTag);
}
}
@@ -173,11 +175,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* This method can be called by each of the publisher threads. As a result all changes to the channel object must be
* thread safe.
*
+ *
* @param entry The message to send
+ * @param batch
* @throws AMQException
*/
@Override
- public void send(QueueEntry entry) throws AMQException
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
// if we do not need to wait for client acknowledgements
// we can decrement the reference count immediately.
@@ -193,6 +197,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
synchronized (getChannel())
{
+ getChannel().getProtocolSession().setDeferFlush(batch);
long deliveryTag = getChannel().getNextDeliveryTag();
sendToClient(entry, deliveryTag);
@@ -234,7 +239,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
public boolean wouldSuspend(QueueEntry msg)
{
- return !getCreditManager().useCreditForMessage(msg.getMessage());
+ return !getCreditManager().useCreditForMessage(msg.getMessage().getSize());
}
}
@@ -263,11 +268,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* This method can be called by each of the publisher threads. As a result all changes to the channel object must be
* thread safe.
*
+ *
* @param entry The message to send
+ * @param batch
* @throws AMQException
*/
@Override
- public void send(QueueEntry entry) throws AMQException
+ public void send(QueueEntry entry, boolean batch) throws AMQException
{
// if we do not need to wait for client acknowledgements
@@ -282,6 +289,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
synchronized (getChannel())
{
+ getChannel().getProtocolSession().setDeferFlush(batch);
long deliveryTag = getChannel().getNextDeliveryTag();
@@ -441,10 +449,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
* This method can be called by each of the publisher threads. As a result all changes to the channel object must be
* thread safe.
*
- * @param msg The message to send
+ *
+ * @param entry
+ * @param batch
* @throws AMQException
*/
- abstract public void send(QueueEntry msg) throws AMQException;
+ abstract public void send(QueueEntry entry, boolean batch) throws AMQException;
public boolean isSuspended()
@@ -575,7 +585,12 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
public boolean wouldSuspend(QueueEntry msg)
{
- return !_creditManager.useCreditForMessage(msg.getMessage());//_channel.wouldSuspend(msg.getMessage());
+ return !_creditManager.useCreditForMessage(msg.getMessage().getSize());//_channel.wouldSuspend(msg.getMessage());
+ }
+
+ public boolean trySendLock()
+ {
+ return _stateChangeLock.tryLock();
}
public void getSendLock()
@@ -623,13 +638,16 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
restoreCredit(queueEntry);
}
+ public void releaseQueueEntry(final QueueEntry queueEntry)
+ {
+ restoreCredit(queueEntry);
+ }
+
public void restoreCredit(final QueueEntry queueEntry)
{
_creditManager.restoreCredit(1, queueEntry.getSize());
}
-
-
public void creditStateChanged(boolean hasCredit)
{
@@ -821,4 +839,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage
confirmAutoClose();
}
}
+
+ public void flushBatched()
+ {
+ _channel.getProtocolSession().setDeferFlush(false);
+
+ _channel.getProtocolSession().flushBatched();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
index d9845c5fa6..6db58ce9c1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
@@ -24,12 +24,15 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SUBSCRIPT
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.QUEUE_FORMAT;
import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.BaseQueue;
+import org.apache.qpid.server.queue.InboundMessageAdapter;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.configuration.ConfigStore;
import org.apache.qpid.server.configuration.ConfiguredObject;
import org.apache.qpid.server.configuration.SessionConfig;
import org.apache.qpid.server.configuration.SubscriptionConfig;
import org.apache.qpid.server.configuration.SubscriptionConfigType;
+import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.flow.CreditCreditManager;
import org.apache.qpid.server.flow.WindowCreditManager;
@@ -37,9 +40,11 @@ import org.apache.qpid.server.flow.FlowCreditManager_0_10;
import org.apache.qpid.server.filter.FilterManager;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.GenericActor;
+import org.apache.qpid.server.logging.messages.ChannelMessages;
import org.apache.qpid.server.logging.messages.SubscriptionMessages;
import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.message.InboundMessage;
import org.apache.qpid.server.message.ServerMessage;
import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.server.message.AMQMessage;
@@ -56,6 +61,8 @@ import org.apache.qpid.transport.MessageFlowMode;
import org.apache.qpid.transport.MessageProperties;
import org.apache.qpid.transport.MessageTransfer;
import org.apache.qpid.transport.Method;
+import org.apache.qpid.transport.Option;
+import org.apache.qpid.transport.Session;
import org.apache.qpid.transport.Struct;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
@@ -79,11 +86,14 @@ import java.nio.ByteBuffer;
public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener, SubscriptionConfig, LogSubject
{
+
private final long _subscriptionID;
private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this);
private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this);
+ private static final Option[] BATCHED = new Option[] { Option.BATCH };
+
private final Lock _stateChangeLock = new ReentrantLock();
private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE);
@@ -120,6 +130,8 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
private final long _createTime = System.currentTimeMillis();
private final AtomicLong _deliveredCount = new AtomicLong(0);
private final Map<String, Object> _arguments;
+ private int _deferredMessageCredit;
+ private long _deferredSizeCredit;
public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode,
@@ -130,6 +142,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
{
_subscriptionID = subscriptionId;
_session = session;
+ _postIdSettingAction = new AddMessageDispositionListenerAction(session);
_destination = destination;
_acceptMode = acceptMode;
_acquireMode = acquireMode;
@@ -204,13 +217,13 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
return false;
}
-
-
- if (_noLocal
- && (entry.getMessage() instanceof MessageTransferMessage)
- && ((MessageTransferMessage)entry.getMessage()).getSession() == _session)
+ if (_noLocal && entry.getMessage() instanceof MessageTransferMessage)
{
- return false;
+ Session messageSession= ((MessageTransferMessage)entry.getMessage()).getSession();
+ if (messageSession != null && messageSession.getConnection() == _session.getConnection())
+ {
+ return false;
+ }
}
@@ -307,10 +320,26 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
}
- private class AddMessageDispositionListnerAction implements Runnable
+ public static class AddMessageDispositionListenerAction implements Runnable
{
- public MessageTransfer _xfr;
- public ServerSession.MessageDispositionChangeListener _action;
+ private MessageTransfer _xfr;
+ private ServerSession.MessageDispositionChangeListener _action;
+ private ServerSession _session;
+
+ public AddMessageDispositionListenerAction(ServerSession session)
+ {
+ _session = session;
+ }
+
+ public void setXfr(MessageTransfer xfr)
+ {
+ _xfr = xfr;
+ }
+
+ public void setAction(ServerSession.MessageDispositionChangeListener action)
+ {
+ _action = action;
+ }
public void run()
{
@@ -321,9 +350,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
}
}
- private final AddMessageDispositionListnerAction _postIdSettingAction = new AddMessageDispositionListnerAction();
+ private final AddMessageDispositionListenerAction _postIdSettingAction;
- public void send(final QueueEntry entry) throws AMQException
+ public void send(final QueueEntry entry, boolean batch) throws AMQException
{
ServerMessage serverMsg = entry.getMessage();
@@ -568,27 +597,29 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
{
public void onComplete(Method method)
{
- restoreCredit(entry);
+ deferredAddCredit(1, entry.getSize());
}
});
}
- _postIdSettingAction._xfr = xfr;
+ _postIdSettingAction.setXfr(xfr);
if(_acceptMode == MessageAcceptMode.EXPLICIT)
{
- _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this);
+ _postIdSettingAction.setAction(new ExplicitAcceptDispositionChangeListener(entry, this));
}
else if(_acquireMode != MessageAcquireMode.PRE_ACQUIRED)
{
- _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this);
+ _postIdSettingAction.setAction(new ImplicitAcceptDispositionChangeListener(entry, this));
}
else
{
- _postIdSettingAction._action = null;
+ _postIdSettingAction.setAction(null);
}
+
_session.sendMessage(xfr, _postIdSettingAction);
+ entry.incrementDeliveryCount();
_deliveredCount.incrementAndGet();
if(_acceptMode == MessageAcceptMode.NONE && _acquireMode == MessageAcquireMode.PRE_ACQUIRED)
{
@@ -624,17 +655,74 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
});
}
- void reject(QueueEntry entry)
+ void reject(final QueueEntry entry)
{
entry.setRedelivered();
entry.routeToAlternate();
}
- void release(QueueEntry entry)
+ void release(final QueueEntry entry, final boolean setRedelivered)
{
- entry.setRedelivered();
- entry.release();
+ if (setRedelivered)
+ {
+ entry.setRedelivered();
+ }
+
+ if (getSession().isClosing() || !setRedelivered)
+ {
+ entry.decrementDeliveryCount();
+ }
+
+ if (isMaxDeliveryLimitReached(entry))
+ {
+ sendToDLQOrDiscard(entry);
+ }
+ else
+ {
+ entry.release();
+ }
+ }
+
+ protected void sendToDLQOrDiscard(QueueEntry entry)
+ {
+ final Exchange alternateExchange = entry.getQueue().getAlternateExchange();
+ final LogActor logActor = CurrentActor.get();
+ final ServerMessage msg = entry.getMessage();
+ if (alternateExchange != null)
+ {
+ final InboundMessage m = new InboundMessageAdapter(entry);
+
+ final ArrayList<? extends BaseQueue> destinationQueues = alternateExchange.route(m);
+
+ if (destinationQueues == null || destinationQueues.isEmpty())
+ {
+ entry.discard();
+
+ logActor.message( ChannelMessages.DISCARDMSG_NOROUTE(msg.getMessageNumber(), alternateExchange.getName()));
+ }
+ else
+ {
+ entry.routeToAlternate();
+
+ //output operational logging for each delivery post commit
+ for (final BaseQueue destinationQueue : destinationQueues)
+ {
+ logActor.message( ChannelMessages.DEADLETTERMSG(msg.getMessageNumber(), destinationQueue.getNameShortString().asString()));
+ }
+ }
+ }
+ else
+ {
+ entry.discard();
+ logActor.message(ChannelMessages.DISCARDMSG_NOALTEXCH(msg.getMessageNumber(), entry.getQueue().getName(), msg.getRoutingKey()));
+ }
+ }
+
+ private boolean isMaxDeliveryLimitReached(QueueEntry entry)
+ {
+ final int maxDeliveryLimit = entry.getQueue().getMaximumDeliveryCount();
+ return (maxDeliveryLimit > 0 && entry.getDeliveryCount() >= maxDeliveryLimit);
}
public void queueDeleted(AMQQueue queue)
@@ -642,9 +730,14 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
_deleted.set(true);
}
- public boolean wouldSuspend(QueueEntry msg)
+ public boolean wouldSuspend(QueueEntry entry)
{
- return !_creditManager.useCreditForMessage(msg.getMessage());
+ return !_creditManager.useCreditForMessage(entry.getMessage().getSize());
+ }
+
+ public boolean trySendLock()
+ {
+ return _stateChangeLock.tryLock();
}
public void getSendLock()
@@ -664,7 +757,12 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
public void onDequeue(QueueEntry queueEntry)
{
+ // no-op for 0-10, credit restored by completing command.
+ }
+ public void releaseQueueEntry(QueueEntry queueEntry)
+ {
+ // no-op for 0-10, credit restored by completing command.
}
public void setStateListener(StateListener listener)
@@ -702,6 +800,28 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
return _properties.get(key);
}
+ private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit)
+ {
+ _deferredMessageCredit += deferredMessageCredit;
+ _deferredSizeCredit += deferredSizeCredit;
+
+ }
+
+ public void flushCreditState()
+ {
+ flushCreditState(false);
+ }
+ public void flushCreditState(boolean strict)
+ {
+ if(strict || !isSuspended() || _deferredMessageCredit >= 200
+ || !(_creditManager instanceof WindowCreditManager)
+ || ((WindowCreditManager)_creditManager).getMessageCreditLimit() < 400 )
+ {
+ _creditManager.restoreCredit(_deferredMessageCredit, _deferredSizeCredit);
+ _deferredMessageCredit = 0;
+ _deferredSizeCredit = 0l;
+ }
+ }
public FlowCreditManager_0_10 getCreditManager()
{
@@ -804,6 +924,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
public void flush() throws AMQException
{
+ flushCreditState(true);
_queue.flushSubscription(this);
stop();
}
@@ -947,4 +1068,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr
return (LogSubject) this;
}
+
+ public void flushBatched()
+ {
+ _session.getConnection().flush();
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
index e18b453db3..00f0c9f0f1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
@@ -24,6 +24,14 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CONNECTIO
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SOCKET_FORMAT;
import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.USER_FORMAT;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.JMException;
+
+import org.apache.qpid.server.management.ManagedObject;
+
+import org.apache.qpid.server.management.Managable;
+
import java.security.Principal;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -55,7 +63,7 @@ import org.apache.qpid.transport.Method;
import org.apache.qpid.transport.ProtocolEvent;
import org.apache.qpid.transport.Session;
-public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject, AuthorizationHolder
+public class ServerConnection extends Connection implements Managable, AMQConnectionModel, LogSubject, AuthorizationHolder
{
private ConnectionConfig _config;
private Runnable _onOpenTask;
@@ -67,6 +75,10 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
private boolean _statisticsEnabled = false;
private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
private final long _connectionId;
+
+ private ServerConnectionMBean _mBean;
+ private VirtualHost _virtualHost;
+ private AtomicLong _lastIoTime = new AtomicLong();
public ServerConnection(final long connectionId)
{
@@ -133,9 +145,6 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
super.setConnectionDelegate(delegate);
}
- private VirtualHost _virtualHost;
-
-
public VirtualHost getVirtualHost()
{
return _virtualHost;
@@ -144,8 +153,18 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void setVirtualHost(VirtualHost virtualHost)
{
_virtualHost = virtualHost;
-
+
initialiseStatistics();
+
+ try
+ {
+ _mBean = new ServerConnectionMBean(this);
+ _mBean.register();
+ }
+ catch (JMException jme)
+ {
+ log.error("Unable to create mBean for ServerConnection",jme);
+ }
}
public void setConnectionConfig(final ConnectionConfig config)
@@ -190,6 +209,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
@Override
public void received(ProtocolEvent event)
{
+ _lastIoTime.set(System.currentTimeMillis());
if (event.isConnectionControl())
{
CurrentActor.set(_actor);
@@ -260,6 +280,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void close(AMQConstant cause, String message) throws AMQException
{
closeSubscriptions();
+ if (_mBean != null)
+ {
+ _mBean.unregister();
+ _mBean = null;
+ }
ConnectionCloseCode replyCode = ConnectionCloseCode.NORMAL;
try
{
@@ -405,6 +430,11 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
public void closed()
{
closeSubscriptions();
+ if (_mBean != null)
+ {
+ _mBean.unregister();
+ _mBean = null;
+ }
super.closed();
}
@@ -416,4 +446,38 @@ public class ServerConnection extends Connection implements AMQConnectionModel,
}
}
+ public void receivedComplete()
+ {
+ for (Session ssn : getChannels())
+ {
+ ((ServerSession)ssn).flushCreditState();
+ }
+ }
+
+ @Override
+ public ManagedObject getManagedObject()
+ {
+ return _mBean;
+ }
+
+ @Override
+ public void send(ProtocolEvent event)
+ {
+ _lastIoTime.set(System.currentTimeMillis());
+ super.send(event);
+ }
+
+ public AtomicLong getLastIoTime()
+ {
+ return _lastIoTime;
+ }
+
+ void checkForNotification()
+ {
+ int channelsCount = getSessionModels().size();
+ if (_mBean != null && channelsCount >= getConnectionDelegate().getChannelMax())
+ {
+ _mBean.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value");
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
index 8d6e0e0d80..66ed6f1e62 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -28,10 +28,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
-
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
-
import org.apache.qpid.common.ServerPropertyNames;
import org.apache.qpid.protocol.ProtocolEngine;
import org.apache.qpid.server.configuration.BrokerConfig;
@@ -49,6 +47,7 @@ import org.apache.qpid.transport.ConnectionClose;
import org.apache.qpid.transport.ConnectionCloseCode;
import org.apache.qpid.transport.ConnectionOpen;
import org.apache.qpid.transport.ConnectionOpenOk;
+import org.apache.qpid.transport.ConnectionStartOk;
import org.apache.qpid.transport.ConnectionTuneOk;
import org.apache.qpid.transport.ServerDelegate;
import org.apache.qpid.transport.Session;
@@ -62,6 +61,8 @@ public class ServerConnectionDelegate extends ServerDelegate
{
private final String _localFQDN;
private final IApplicationRegistry _appRegistry;
+ private int _maxNoOfChannels;
+ private Map<String,Object> _clientProperties;
public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN)
{
@@ -77,6 +78,7 @@ public class ServerConnectionDelegate extends ServerDelegate
_appRegistry = appRegistry;
_localFQDN = localFQDN;
+ _maxNoOfChannels = ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount();
}
private static Map<String, Object> createConnectionProperties(final BrokerConfig brokerConfig)
@@ -154,7 +156,7 @@ public class ServerConnectionDelegate extends ServerDelegate
public void connectionOpen(Connection conn, ConnectionOpen open)
{
final ServerConnection sconn = (ServerConnection) conn;
-
+
VirtualHost vhost;
String vhostName;
if(open.hasVirtualHost())
@@ -222,7 +224,12 @@ public class ServerConnectionDelegate extends ServerDelegate
@Override
protected int getChannelMax()
{
- return ApplicationRegistry.getInstance().getConfiguration().getMaxChannelCount();
+ return _maxNoOfChannels;
+ }
+
+ protected void setChannelMax(int channelMax)
+ {
+ _maxNoOfChannels = channelMax;
}
@Override public void sessionDetach(Connection conn, SessionDetach dtc)
@@ -253,6 +260,7 @@ public class ServerConnectionDelegate extends ServerDelegate
{
ssn = sessionAttachImpl(conn, atc);
conn.registerSession(ssn);
+ ((ServerConnection)conn).checkForNotification();
}
else
{
@@ -279,4 +287,16 @@ public class ServerConnectionDelegate extends ServerDelegate
}
return true;
}
+
+ @Override
+ public void connectionStartOk(Connection conn, ConnectionStartOk ok)
+ {
+ _clientProperties = ok.getClientProperties();
+ super.connectionStartOk(conn, ok);
+ }
+
+ public Map<String,Object> getClientProperties()
+ {
+ return _clientProperties;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java
new file mode 100644
index 0000000000..17c7bed601
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java
@@ -0,0 +1,264 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.transport;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import javax.management.JMException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.qpid.common.ClientProperties;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.management.AbstractAMQManagedConnectionObject;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.protocol.AMQSessionModel;
+
+/**
+ * This MBean class implements the management interface. In order to make more attributes, operations and notifications
+ * available over JMX simply augment the ManagedConnection interface and add the appropriate implementation here.
+ */
+@MBeanDescription("Management Bean for an AMQ Broker 0-10 Connection")
+public class ServerConnectionMBean extends AbstractAMQManagedConnectionObject
+{
+ private final ServerConnection _serverConnection;
+
+ @MBeanConstructor("Creates an MBean exposing an AMQ Broker 0-10 Connection")
+ protected ServerConnectionMBean(final ServerConnection serverConnection) throws NotCompliantMBeanException
+ {
+ super(serverConnection.getConfig().getAddress());
+ _serverConnection = serverConnection;
+ }
+
+ @Override
+ public ManagedObject getParentObject()
+ {
+ return _serverConnection.getVirtualHost().getManagedObject();
+ }
+
+ @Override
+ public String getClientId()
+ {
+ return _serverConnection.getClientId();
+ }
+
+ @Override
+ public String getAuthorizedId()
+ {
+ return _serverConnection.getAuthorizedPrincipal().getName();
+ }
+
+ @Override
+ public String getVersion()
+ {
+ return String.valueOf(_serverConnection.getConnectionDelegate().getClientProperties().get(ClientProperties.version.toString()));
+ }
+
+ @Override
+ public String getRemoteAddress()
+ {
+ return _serverConnection.getConfig().getAddress();
+ }
+
+ @Override
+ public Date getLastIoTime()
+ {
+ return new Date(_serverConnection.getLastIoTime().longValue());
+ }
+
+ @Override
+ public Long getMaximumNumberOfChannels()
+ {
+ return (long) _serverConnection.getConnectionDelegate().getChannelMax();
+ }
+
+ @Override
+ public TabularData channels() throws IOException, JMException
+ {
+ final TabularDataSupport channelsList = new TabularDataSupport(_channelsType);
+ final List<AMQSessionModel> list = _serverConnection.getSessionModels();
+
+ for (final AMQSessionModel channel : list)
+ {
+ final ServerSession session = (ServerSession)channel;
+ Object[] itemValues =
+ {
+ session.getChannel(),
+ session.isTransactional(),
+ null,
+ session.getUnacknowledgedMessageCount(),
+ session.getBlocking()
+ };
+
+ final CompositeData channelData = new CompositeDataSupport(_channelType,
+ COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues);
+ channelsList.put(channelData);
+ }
+ return channelsList;
+ }
+
+ @Override
+ public void commitTransactions(int channelId) throws JMException
+ {
+ final ServerSession session = (ServerSession)_serverConnection.getSession(channelId);
+ if (session == null)
+ {
+ throw new JMException("The channel (channel Id = " + channelId + ") does not exist");
+ }
+ else if (session.isTransactional())
+ {
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+ try
+ {
+ session.commit();
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+ }
+
+ @Override
+ public void rollbackTransactions(int channelId) throws JMException
+ {
+ final ServerSession session = (ServerSession)_serverConnection.getSession(channelId);
+ if (session == null)
+ {
+ throw new JMException("The channel (channel Id = " + channelId + ") does not exist");
+ }
+ else if (session.isTransactional())
+ {
+ CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
+ try
+ {
+ session.rollback();
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
+ }
+ }
+
+ @Override
+ public void closeConnection() throws Exception
+ {
+ _serverConnection.mgmtClose();
+ }
+
+ @Override
+ public void resetStatistics() throws Exception
+ {
+ _serverConnection.resetStatistics();
+ }
+
+ @Override
+ public double getPeakMessageDeliveryRate()
+ {
+ return _serverConnection.getMessageDeliveryStatistics().getPeak();
+ }
+
+ @Override
+ public double getPeakDataDeliveryRate()
+ {
+ return _serverConnection.getDataDeliveryStatistics().getPeak();
+ }
+
+ @Override
+ public double getMessageDeliveryRate()
+ {
+ return _serverConnection.getMessageDeliveryStatistics().getRate();
+ }
+
+ @Override
+ public double getDataDeliveryRate()
+ {
+ return _serverConnection.getDataDeliveryStatistics().getRate();
+ }
+
+ @Override
+ public long getTotalMessagesDelivered()
+ {
+ return _serverConnection.getMessageDeliveryStatistics().getTotal();
+ }
+
+ @Override
+ public long getTotalDataDelivered()
+ {
+ return _serverConnection.getDataDeliveryStatistics().getTotal();
+ }
+
+ @Override
+ public double getPeakMessageReceiptRate()
+ {
+ return _serverConnection.getMessageReceiptStatistics().getPeak();
+ }
+
+ @Override
+ public double getPeakDataReceiptRate()
+ {
+ return _serverConnection.getDataReceiptStatistics().getPeak();
+ }
+
+ @Override
+ public double getMessageReceiptRate()
+ {
+ return _serverConnection.getMessageReceiptStatistics().getRate();
+ }
+
+ @Override
+ public double getDataReceiptRate()
+ {
+ return _serverConnection.getDataReceiptStatistics().getRate();
+ }
+
+ @Override
+ public long getTotalMessagesReceived()
+ {
+ return _serverConnection.getMessageReceiptStatistics().getTotal();
+ }
+
+ @Override
+ public long getTotalDataReceived()
+ {
+ return _serverConnection.getDataReceiptStatistics().getTotal();
+ }
+
+ @Override
+ public boolean isStatisticsEnabled()
+ {
+ return _serverConnection.isStatisticsEnabled();
+ }
+
+ @Override
+ public void setStatisticsEnabled(boolean enabled)
+ {
+ _serverConnection.setStatisticsEnabled(enabled);
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
index 429cc4cf66..23b77b1fd9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -37,9 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
-
import javax.security.auth.Subject;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.ProtocolEngine;
@@ -93,7 +91,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
{
public void onAccept();
- public void onRelease();
+ public void onRelease(boolean setRedelivered);
public void onReject();
@@ -230,13 +228,13 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
}
- public void release(RangeSet ranges)
+ public void release(RangeSet ranges, final boolean setRedelivered)
{
dispositionChange(ranges, new MessageDispositionAction()
{
public void performAction(MessageDispositionChangeListener listener)
{
- listener.onRelease();
+ listener.onRelease(setRedelivered);
}
});
}
@@ -350,7 +348,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
_transaction.rollback();
for(MessageDispositionChangeListener listener : _messageDispositionListenerMap.values())
{
- listener.onRelease();
+ listener.onRelease(true);
}
_messageDispositionListenerMap.clear();
@@ -698,4 +696,23 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi
unregister(subscription_0_10);
}
}
+
+ public void flushCreditState()
+ {
+ final Collection<Subscription_0_10> subscriptions = getSubscriptions();
+ for (Subscription_0_10 subscription_0_10 : subscriptions)
+ {
+ subscription_0_10.flushCreditState(false);
+ }
+ }
+
+ public int getUnacknowledgedMessageCount()
+ {
+ return _messageDispositionListenerMap.size();
+ }
+
+ public boolean getBlocking()
+ {
+ return false; //TODO: Blocking not implemented on 0-10 yet.
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
index c87919b478..a0dca53ed0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -100,6 +100,11 @@ public class ServerSessionDelegate extends SessionDelegate
{
private static final Logger LOGGER = Logger.getLogger(ServerSessionDelegate.class);
+ /**
+ * No-local queue argument is used to support the no-local feature of Durable Subscribers.
+ */
+ private static final String QUEUE_ARGUMENT_NO_LOCAL = "no-local";
+
public ServerSessionDelegate()
{
@@ -143,7 +148,7 @@ public class ServerSessionDelegate extends SessionDelegate
@Override
public void messageRelease(Session session, MessageRelease method)
{
- ((ServerSession)session).release(method.getTransfers());
+ ((ServerSession)session).release(method.getTransfers(), method.getSetRedelivered());
}
@Override
@@ -963,13 +968,10 @@ public class ServerSessionDelegate extends SessionDelegate
if(method.hasArguments() && method.getArguments() != null)
{
- if(method.getArguments().containsKey("no-local"))
+ if(method.getArguments().containsKey(QUEUE_ARGUMENT_NO_LOCAL))
{
- Object no_local = method.getArguments().get("no-local");
- if(no_local instanceof Boolean && ((Boolean)no_local))
- {
- queue.setNoLocal(true);
- }
+ Object noLocal = method.getArguments().get(QUEUE_ARGUMENT_NO_LOCAL);
+ queue.setNoLocal(convertBooleanValue(noLocal));
}
}
@@ -1079,6 +1081,30 @@ public class ServerSessionDelegate extends SessionDelegate
}
}
+ /**
+ * Converts a queue argument into a boolean value. For compatibility with the C++
+ * and the clients, accepts with Boolean, String, or Number types.
+ * @param argValue argument value.
+ *
+ * @return true if set
+ */
+ private boolean convertBooleanValue(Object argValue)
+ {
+ if(argValue instanceof Boolean && ((Boolean)argValue))
+ {
+ return true;
+ }
+ else if (argValue instanceof String && Boolean.parseBoolean((String)argValue))
+ {
+ return true;
+ }
+ else if (argValue instanceof Number && ((Number)argValue).intValue() != 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
protected AMQQueue createQueue(final String queueName,
final QueueDeclare body,
VirtualHost virtualHost,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java
index 5c4fe0aab8..248b3b2143 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/SlowConsumerDetection.java
@@ -26,11 +26,13 @@ import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionConfiguration;
import org.apache.qpid.server.configuration.plugins.SlowConsumerDetectionQueueConfiguration;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.plugins.Plugin;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.plugins.logging.SlowConsumerDetectionMessages;
+import org.apache.qpid.slowconsumerdetection.policies.SlowConsumerPolicyPlugin;
public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
{
@@ -56,7 +58,7 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
/**
* Configures the slow consumer disconnect plugin by adding a listener to each exchange on this
- * cirtual host to record all the configured queues in a cache for processing by the housekeeping
+ * virtual host to record all the configured queues in a cache for processing by the housekeeping
* thread.
*
* @see Plugin#configure(ConfigurationPlugin)
@@ -65,9 +67,10 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
{
_config = (SlowConsumerDetectionConfiguration) config;
_listener = new ConfiguredQueueBindingListener(getVirtualHost().getName());
- for (AMQShortString exchangeName : getVirtualHost().getExchangeRegistry().getExchangeNames())
+ final ExchangeRegistry exchangeRegistry = getVirtualHost().getExchangeRegistry();
+ for (AMQShortString exchangeName : exchangeRegistry.getExchangeNames())
{
- getVirtualHost().getExchangeRegistry().getExchange(exchangeName).addBindingListener(_listener);
+ exchangeRegistry.getExchange(exchangeName).addBindingListener(_listener);
}
}
@@ -87,11 +90,21 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
try
{
- SlowConsumerDetectionQueueConfiguration config =
+ final SlowConsumerDetectionQueueConfiguration config =
q.getConfiguration().getConfiguration(SlowConsumerDetectionQueueConfiguration.class.getName());
if (checkQueueStatus(q, config))
{
- config.getPolicy().performPolicy(q);
+ final SlowConsumerPolicyPlugin policy = config.getPolicy();
+ if (policy == null)
+ {
+ // We would only expect to see this during shutdown
+ _logger.warn("No slow consumer policy for queue " + q.getName());
+ }
+ else
+ {
+ policy.performPolicy(q);
+ }
+
}
}
catch (Exception e)
@@ -126,7 +139,10 @@ public class SlowConsumerDetection extends VirtualHostHouseKeepingPlugin
{
if (config != null)
{
- _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config);
+ if (_logger.isInfoEnabled())
+ {
+ _logger.info("Retrieved Queue(" + q.getName() + ") Config:" + config);
+ }
int count = q.getMessageCount();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
deleted file mode 100644
index 2c0ceed80b..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/MessageStoreTool.java
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.OptionBuilder;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.configuration.Configuration;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
-import org.apache.qpid.server.store.MemoryMessageStore;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.tools.messagestore.commands.Clear;
-import org.apache.qpid.tools.messagestore.commands.Command;
-import org.apache.qpid.tools.messagestore.commands.Copy;
-import org.apache.qpid.tools.messagestore.commands.Dump;
-import org.apache.qpid.tools.messagestore.commands.Help;
-import org.apache.qpid.tools.messagestore.commands.List;
-import org.apache.qpid.tools.messagestore.commands.Load;
-import org.apache.qpid.tools.messagestore.commands.Quit;
-import org.apache.qpid.tools.messagestore.commands.Select;
-import org.apache.qpid.tools.messagestore.commands.Show;
-import org.apache.qpid.tools.messagestore.commands.Move;
-import org.apache.qpid.tools.messagestore.commands.Purge;
-import org.apache.qpid.tools.utils.CommandParser;
-import org.apache.qpid.tools.utils.Console;
-import org.apache.qpid.tools.utils.SimpleCommandParser;
-import org.apache.qpid.tools.utils.SimpleConsole;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-/**
- * MessageStoreTool.
- */
-public class MessageStoreTool
-{
- /** Text outputted at the start of each console.*/
- private static final String BOILER_PLATE = "MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances";
-
- /** I/O Wrapper. */
- protected Console _console;
-
- /** Batch mode flag. */
- protected boolean _batchMode;
-
- /** Internal State object. */
- private State _state = new State();
-
- private HashMap<String, Command> _commands = new HashMap<String, Command>();
-
- /** SLF4J Logger. */
- private static Logger _devlog = LoggerFactory.getLogger(MessageStoreTool.class);
-
- /** Loaded configuration file. */
- private Configuration _config;
-
- /** Control used for main run loop. */
- private boolean _running = true;
- private boolean _initialised = false;
-
- //---------------------------------------------------------------------------------------------------/
-
- public static void main(String[] args) throws Configuration.InitException
- {
-
- MessageStoreTool tool = new MessageStoreTool(args);
-
- tool.start();
- }
-
-
- public MessageStoreTool(String[] args) throws Configuration.InitException
- {
- this(args, System.in, System.out);
- }
-
- public MessageStoreTool(String[] args, InputStream in, OutputStream out) throws Configuration.InitException
- {
- BufferedReader consoleReader = new BufferedReader(new InputStreamReader(in));
- BufferedWriter consoleWriter = new BufferedWriter(new OutputStreamWriter(out));
-
- Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(this)));
- _batchMode = false;
-
- _console = new SimpleConsole(consoleWriter, consoleReader);
-
- _config = new Configuration();
-
- setOptions();
- _config.processCommandline(args);
- }
-
-
- private void setOptions()
- {
- Option help = new Option("h", "help", false, "print this message");
- Option version = new Option("v", "version", false, "print the version information and exit");
- Option configFile =
- OptionBuilder.withArgName("file").hasArg()
- .withDescription("use given configuration file By "
- + "default looks for a file named "
- + Configuration.DEFAULT_CONFIG_FILE + " in " + Configuration.QPID_HOME)
- .withLongOpt("config")
- .create("c");
-
- _config.setOption(help);
- _config.setOption(version);
- _config.setOption(configFile);
- }
-
- public State getState()
- {
- return _state;
- }
-
- public Map<String, Command> getCommands()
- {
- return _commands;
- }
-
- public void setConfigurationFile(String configfile) throws Configuration.InitException
- {
- _config.loadConfig(new File(configfile));
- setup();
- }
-
- public Console getConsole()
- {
- return _console;
- }
-
- public void setConsole(Console console)
- {
- _console = console;
- }
-
- /**
- * Simple ShutdownHook to cleanly shutdown the databases
- */
- static class ShutdownHook implements Runnable
- {
- MessageStoreTool _tool;
-
- ShutdownHook(MessageStoreTool messageStoreTool)
- {
- _tool = messageStoreTool;
- }
-
- public void run()
- {
- _tool.quit();
- }
- }
-
- public void quit()
- {
- _running = false;
-
- if (_initialised)
- {
- ApplicationRegistry.remove();
- }
-
- _console.println("...exiting");
-
- _console.close();
- }
-
- public void setBatchMode(boolean batchmode)
- {
- _batchMode = batchmode;
- }
-
- /**
- * Main loop
- */
- protected void start()
- {
- setup();
-
- if (!_initialised)
- {
- System.exit(1);
- }
-
- _console.println("");
-
- _console.println(BOILER_PLATE);
-
- runCLI();
- }
-
- private void setup()
- {
- loadDefaultVirtualHosts();
-
- loadCommands();
-
- _state.clearAll();
- }
-
- private void loadCommands()
- {
- _commands.clear();
- //todo Dynamically load the classes that exis in com.redhat.etp.qpid.commands
- _commands.put("close", new Clear(this));
- _commands.put("copy", new Copy(this));
- _commands.put("dump", new Dump(this));
- _commands.put("help", new Help(this));
- _commands.put("list", new List(this));
- _commands.put("load", new Load(this));
- _commands.put("move", new Move(this));
- _commands.put("purge", new Purge(this));
- _commands.put("quit", new Quit(this));
- _commands.put("select", new Select(this));
- _commands.put("show", new Show(this));
- }
-
- private void loadDefaultVirtualHosts()
- {
- final File configFile = _config.getConfigFile();
-
- loadVirtualHosts(configFile);
- }
-
- private void loadVirtualHosts(File configFile)
- {
-
- if (!configFile.exists())
- {
- _devlog.error("Config file not found:" + configFile.getAbsolutePath());
- return;
- }
- else
- {
- _devlog.debug("using config file :" + configFile.getAbsolutePath());
- }
-
- try
- {
- ConfigurationFileApplicationRegistry registry = new ConfigurationFileApplicationRegistry(configFile);
-
- ApplicationRegistry.remove();
-
- ApplicationRegistry.initialise(registry);
-
- checkMessageStores();
- _initialised = true;
- }
- catch (ConfigurationException e)
- {
- _console.println("Unable to load configuration due to configuration error: " + e.getMessage());
- e.printStackTrace();
- }
- catch (Exception e)
- {
- _console.println("Unable to load configuration due to: " + e.getMessage());
- e.printStackTrace();
- }
-
-
- }
-
- private void checkMessageStores()
- {
- Collection<VirtualHost> vhosts = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts();
-
- boolean warning = false;
- for (VirtualHost vhost : vhosts)
- {
- if (vhost.getMessageStore() instanceof MemoryMessageStore)
- {
- _console.println("WARNING: Virtualhost '" + vhost.getName() + "' is using a MemoryMessageStore. "
- + "Changes will not persist.");
- warning = true;
- }
- }
-
- if (warning)
- {
- _console.println("");
- _console.println("Please ensure you are using the correct config file currently using '"
- + _config.getConfigFile().getAbsolutePath() + "'");
- _console.println("New config file can be specifed by 'load <config file>' or -c on the commandline.");
- _console.println("");
- }
- }
-
- private void runCLI()
- {
- while (_running)
- {
- if (!_batchMode)
- {
- printPrompt();
- }
-
- String[] args = _console.readCommand();
-
- while (args != null)
- {
- exec(args);
-
- if (_running)
- {
- if (!_batchMode)
- {
- printPrompt();
- }
-
- args = _console.readCommand();
- }
- }
- }
- }
-
- private void printPrompt()
- {
- _console.print(prompt());
- }
-
-
- /**
- * Execute a script (batch mode).
- *
- * @param script The file script
- */
- protected void runScripts(String script)
- {
- //Store Current State
- boolean oldBatch = _batchMode;
- CommandParser oldParser = _console.getCommandParser();
- setBatchMode(true);
-
- try
- {
- _devlog.debug("Running script '" + script + "'");
-
- _console.setCommandParser(new SimpleCommandParser(new BufferedReader(new FileReader(script))));
-
- start();
- }
- catch (java.io.FileNotFoundException e)
- {
- _devlog.error("Script not found: '" + script + "' due to:" + e.getMessage());
- }
-
- //Restore previous state
- _console.setCommandParser(oldParser);
- setBatchMode(oldBatch);
- }
-
- public String prompt()
- {
- String state = _state.toString();
- if (state != null && state.length() != 0)
- {
- return state + ":bdb$ ";
- }
- else
- {
- return "bdb$ ";
- }
- }
-
- /**
- * Execute the command.
- *
- * @param args [command, arg0, arg1...].
- */
- protected void exec(String[] args)
- {
- // Comment lines start with a #
- if (args.length == 0 || args[0].startsWith("#"))
- {
- return;
- }
-
- final String command = args[0];
-
- Command cmd = _commands.get(command);
-
- if (cmd == null)
- {
- _console.println("Command not understood: " + command);
- }
- else
- {
- cmd.execute(args);
- }
- }
-
-
- /**
- * Displays usage info.
- */
- protected static void help()
- {
- System.out.println(BOILER_PLATE);
- System.out.println("Usage: java " + MessageStoreTool.class + " [Options]");
- System.out.println(" [-c <broker config file>] : Defaults to \"$QPID_HOME/etc/config.xml\"");
- }
-
-
- /**
- * This class is used to store the current state of the tool.
- *
- * This is then interrogated by the various commands to augment their behaviour.
- *
- *
- */
- public static class State
- {
- private VirtualHost _vhost = null;
- private AMQQueue _queue = null;
- private Exchange _exchange = null;
- private java.util.List<Long> _msgids = null;
-
- public State()
- {
- }
-
- public void setQueue(AMQQueue queue)
- {
- _queue = queue;
- }
-
- public AMQQueue getQueue()
- {
- return _queue;
- }
-
- public void setVhost(VirtualHost vhost)
- {
- _vhost = vhost;
- }
-
- public VirtualHost getVhost()
- {
- return _vhost;
- }
-
- public Exchange getExchange()
- {
- return _exchange;
- }
-
- public void setExchange(Exchange exchange)
- {
- _exchange = exchange;
- }
-
- public String toString()
- {
- StringBuilder status = new StringBuilder();
-
- if (_vhost != null)
- {
- status.append(_vhost.getName());
-
- if (_exchange != null)
- {
- status.append("[");
- status.append(_exchange.getNameShortString());
- status.append("]");
-
- if (_queue != null)
- {
- status.append("->'");
- status.append(_queue.getNameShortString());
- status.append("'");
-
- if (_msgids != null)
- {
- status.append(printMessages());
- }
- }
- }
- }
-
- return status.toString();
- }
-
-
- public String printMessages()
- {
- StringBuilder sb = new StringBuilder();
-
- Long previous = null;
-
- Long start = null;
- for (Long id : _msgids)
- {
- if (previous != null)
- {
- if (id == previous + 1)
- {
- if (start == null)
- {
- start = previous;
- }
- }
- else
- {
- if (start != null)
- {
- sb.append(",");
- sb.append(start);
- sb.append("-");
- sb.append(id);
- start = null;
- }
- else
- {
- sb.append(",");
- sb.append(previous);
- }
- }
- }
-
- previous = id;
- }
-
- if (start != null)
- {
- sb.append(",");
- sb.append(start);
- sb.append("-");
- sb.append(_msgids.get(_msgids.size() - 1));
- }
- else
- {
- sb.append(",");
- sb.append(previous);
- }
-
- // surround list in ()
- sb.replace(0, 1, "(");
- sb.append(")");
- return sb.toString();
- }
-
- public void clearAll()
- {
- _vhost = null;
- clearExchange();
- }
-
- public void clearExchange()
- {
- _exchange = null;
- clearQueue();
- }
-
- public void clearQueue()
- {
- _queue = null;
- clearMessages();
- }
-
- public void clearMessages()
- {
- _msgids = null;
- }
-
- /**
- * A common location to provide parsing of the message id string
- * utilised by a number of the commands.
- * The String is comma separated list of ids that can be individual ids
- * or a range (4-10)
- *
- * @param msgString string of msg ids to parse 1,2,4-10
- */
- public void setMessages(String msgString)
- {
- StringTokenizer tok = new StringTokenizer(msgString, ",");
-
- if (tok.hasMoreTokens())
- {
- _msgids = new LinkedList<Long>();
- }
-
- while (tok.hasMoreTokens())
- {
- String next = tok.nextToken();
- if (next.contains("-"))
- {
- Long start = Long.parseLong(next.substring(0, next.indexOf("-")));
- Long end = Long.parseLong(next.substring(next.indexOf("-") + 1));
-
- if (end >= start)
- {
- for (long l = start; l <= end; l++)
- {
- _msgids.add(l);
- }
- }
- }
- else
- {
- _msgids.add(Long.parseLong(next));
- }
- }
-
- }
-
- public void setMessages(java.util.List<Long> msgids)
- {
- _msgids = msgids;
- }
-
- public java.util.List<Long> getMessages()
- {
- return _msgids;
- }
- }//Class State
-
-}//Class MessageStoreTool
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java
deleted file mode 100644
index 5444197cb4..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/AbstractCommand.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-public abstract class AbstractCommand implements Command
-{
- protected Console _console;
- protected MessageStoreTool _tool;
-
- public AbstractCommand(MessageStoreTool tool)
- {
- _console = tool.getConsole();
- _tool = tool;
- }
-
- public void setOutput(Console out)
- {
- _console = out;
- }
-
- protected void commandError(String message, String[] args)
- {
- _console.print(getCommand() + " : " + message);
-
- if (args != null)
- {
- for (int i = 1; i < args.length; i++)
- {
- _console.print(args[i]);
- }
- }
- _console.println("");
- _console.println(help());
- }
-
-
- public abstract String help();
-
- public abstract String usage();
-
- public abstract String getCommand();
-
-
- public abstract void execute(String... args);
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java
deleted file mode 100644
index b0006b3fe6..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Clear.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-public class Clear extends AbstractCommand
-{
- public Clear(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Clears any selection.";
- }
-
- public String usage()
- {
- return "clear [ all | virtualhost | exchange | queue | msgs ]";
- }
-
- public String getCommand()
- {
- return "clear";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length < 1)
- {
- doClose("all");
- }
- else
- {
- doClose(args[1]);
- }
- }
-
- private void doClose(String type)
- {
- if (type.equals("virtualhost")
- || type.equals("all"))
- {
- _tool.getState().clearAll();
- }
-
- if (type.equals("exchange"))
- {
- _tool.getState().clearExchange();
- }
-
- if (type.equals("queue"))
- {
- _tool.getState().clearQueue();
- }
-
- if (type.equals("msgs"))
- {
- _tool.getState().clearMessages();
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java
deleted file mode 100644
index bfa775a34a..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Command.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.utils.Console;
-
-public interface Command
-{
- public void setOutput(Console out);
-
- public String help();
-
- public abstract String usage();
-
- String getCommand();
-
- public void execute(String... args);
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
deleted file mode 100644
index 348c95572d..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.txn.ServerTransaction;
-import org.apache.qpid.server.txn.LocalTransaction;
-
-public class Copy extends Move
-{
- public Copy(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Copy messages between queues.";/*\n" +
- "The currently selected message set will be copied to the specifed queue.\n" +
- "Alternatively the values can be provided on the command line."; */
- }
-
- public String usage()
- {
- return "copy to=<queue> [from=<queue>] [msgids=<msgids eg, 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "copy";
- }
-
- protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue)
- {
- ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog());
- fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getNameShortString().toString(), txn);
- txn.commit();
- }
-
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
deleted file mode 100644
index 8bb5d02b01..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.commons.codec.binary.Hex;
-import org.apache.qpid.server.queue.QueueEntryImpl;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.io.UnsupportedEncodingException;
-import java.util.LinkedList;
-import java.util.List;
-
-public class Dump extends Show
-{
- private static final int LINE_SIZE = 8;
- private static final String DEFAULT_ENCODING = "utf-8";
- private static final boolean SPACE_BYTES = true;
- private static final String BYTE_SPACER = " ";
- private static final String NON_PRINTING_ASCII_CHAR = "?";
-
- protected boolean _content = true;
-
- public Dump(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Dump selected message content. Default: show=content";
- }
-
- public String usage()
- {
- return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=<msgid e.g. 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "dump";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
-
- if (args.length >= 2)
- {
- for (String arg : args)
- {
- if (arg.startsWith("show="))
- {
- _content = arg.contains("content") || arg.contains("all");
- }
- }
-
- parseArgs(args);
- }
-
- performShow();
- }
-
-
- protected List<List> createMessageData(java.util.List<Long> msgids, List<QueueEntry> messages, boolean showHeaders, boolean showRouting,
- boolean showMessageHeaders)
- {
-
- List<List> display = new LinkedList<List>();
-
- List<String> hex = new LinkedList<String>();
- List<String> ascii = new LinkedList<String>();
- display.add(hex);
- display.add(ascii);
-
- for (QueueEntry entry : messages)
- {
- ServerMessage msg = entry.getMessage();
- if (!includeMsg(msg, msgids))
- {
- continue;
- }
-
- //Add divider between messages
- hex.add(Console.ROW_DIVIDER);
- ascii.add(Console.ROW_DIVIDER);
-
- // Show general message information
- hex.add(Show.Columns.ID.name());
- ascii.add(msg.getMessageNumber().toString());
-
- hex.add(Console.ROW_DIVIDER);
- ascii.add(Console.ROW_DIVIDER);
-
- if (showRouting)
- {
- addShowInformation(hex, ascii, msg, "Routing Details", true, false, false);
- }
- if (showHeaders)
- {
- addShowInformation(hex, ascii, msg, "Headers", false, true, false);
- }
- if (showMessageHeaders)
- {
- addShowInformation(hex, ascii, msg, null, false, false, true);
- }
-
- // Add Content Body section
- hex.add("Content Body");
- ascii.add("");
- hex.add(Console.ROW_DIVIDER);
- ascii.add(Console.ROW_DIVIDER);
-
-
- final int messageSize = (int) msg.getSize();
- if (messageSize != 0)
- {
- hex.add("Hex");
- hex.add(Console.ROW_DIVIDER);
-
-
- ascii.add("ASCII");
- ascii.add(Console.ROW_DIVIDER);
-
- java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(64 * 1024);
-
- int position = 0;
-
- while(position < messageSize)
- {
-
- position += msg.getContent(buf, position);
- buf.flip();
- //Duplicate so we don't destroy original data :)
- java.nio.ByteBuffer hexBuffer = buf;
-
- java.nio.ByteBuffer charBuffer = hexBuffer.duplicate();
-
- Hex hexencoder = new Hex();
-
- while (hexBuffer.hasRemaining())
- {
- byte[] line = new byte[LINE_SIZE];
-
- int bufsize = hexBuffer.remaining();
- if (bufsize < LINE_SIZE)
- {
- hexBuffer.get(line, 0, bufsize);
- }
- else
- {
- bufsize = line.length;
- hexBuffer.get(line);
- }
-
- byte[] encoded = hexencoder.encode(line);
-
- try
- {
- String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING);
- String hexLine = "";
-
- int strLength = encStr.length();
- for (int c = 0; c < strLength; c++)
- {
- hexLine += encStr.charAt(c);
-
- if ((c & 1) == 1 && SPACE_BYTES)
- {
- hexLine += BYTE_SPACER;
- }
- }
-
- hex.add(hexLine);
- }
- catch (UnsupportedEncodingException e)
- {
- _console.println(e.getMessage());
- return null;
- }
- }
-
- while (charBuffer.hasRemaining())
- {
- String asciiLine = "";
-
- for (int pos = 0; pos < LINE_SIZE; pos++)
- {
- if (charBuffer.hasRemaining())
- {
- byte ch = charBuffer.get();
-
- if (isPrintable(ch))
- {
- asciiLine += (char) ch;
- }
- else
- {
- asciiLine += NON_PRINTING_ASCII_CHAR;
- }
-
- if (SPACE_BYTES)
- {
- asciiLine += BYTE_SPACER;
- }
- }
- else
- {
- break;
- }
- }
-
- ascii.add(asciiLine);
- }
- buf.clear();
- }
- }
- else
- {
- List<String> result = new LinkedList<String>();
-
- display.add(result);
- result.add("No ContentBodies");
- }
- }
-
- // if hex is empty then we have no data to display
- if (hex.size() == 0)
- {
- return null;
- }
-
- return display;
- }
-
- private void addShowInformation(List<String> column1, List<String> column2, ServerMessage msg,
- String title, boolean routing, boolean headers, boolean messageHeaders)
- {
- List<QueueEntry> single = new LinkedList<QueueEntry>();
- single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE));
-
- List<List> routingData = super.createMessageData(null, single, headers, routing, messageHeaders);
-
- //Reformat data
- if (title != null)
- {
- column1.add(title);
- column2.add("");
- column1.add(Console.ROW_DIVIDER);
- column2.add(Console.ROW_DIVIDER);
- }
-
- // look at all columns in the routing Data
- for (List item : routingData)
- {
- // the item should be:
- // Title
- // *divider
- // value
- // otherwise we can't reason about the correct value
- if (item.size() == 3)
- {
- //Filter out the columns we are not interested in.
-
- String columnName = item.get(0).toString();
-
- if (!(columnName.equals(Show.Columns.ID.name())
- || columnName.equals(Show.Columns.Size.name())))
- {
- column1.add(columnName);
- column2.add(item.get(2).toString());
- }
- }
- }
- column1.add(Console.ROW_DIVIDER);
- column2.add(Console.ROW_DIVIDER);
- }
-
- private boolean isPrintable(byte c)
- {
- return c > 31 && c < 127;
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java
deleted file mode 100644
index 0f9546541b..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Help.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.util.LinkedList;
-import java.util.Map;
-
-public class Help extends AbstractCommand
-{
- public Help(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Provides detailed help on commands.";
- }
-
- public String getCommand()
- {
- return "help";
- }
-
- public String usage()
- {
- return "help [<command>]";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length > 1)
- {
- Command command = _tool.getCommands().get(args[1]);
- if (command != null)
- {
- _console.println(command.help());
- _console.println("Usage:" + command.usage());
- }
- else
- {
- commandError("Command not found: ", args);
- }
- }
- else
- {
- java.util.List<java.util.List> data = new LinkedList<java.util.List>();
-
- java.util.List<String> commandName = new LinkedList<String>();
- java.util.List<String> commandDescription = new LinkedList<String>();
-
- data.add(commandName);
- data.add(commandDescription);
-
- //Set up Headers
- commandName.add("Command");
- commandDescription.add("Description");
-
- commandName.add(Console.ROW_DIVIDER);
- commandDescription.add(Console.ROW_DIVIDER);
-
- //Add current Commands with descriptions
- Map<String, Command> commands = _tool.getCommands();
-
- for (Command command : commands.values())
- {
- commandName.add(command.getCommand());
- commandDescription.add(command.help());
- }
-
- _console.printMap("Available Commands", data);
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
deleted file mode 100644
index 3c4a0c8fac..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.util.Collection;
-import java.util.LinkedList;
-
-public class List extends AbstractCommand
-{
-
- public List(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public void setOutput(Console out)
- {
- _console = out;
- }
-
- public String help()
- {
- return "list available items.";
- }
-
- public String usage()
- {
- return "list queues [<exchange>] | exchanges | bindings [<exchange>] | all";
- }
-
- public String getCommand()
- {
- return "list";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length > 1)
- {
- if ((args[1].equals("exchanges"))
- || (args[1].equals("queues"))
- || (args[1].equals("bindings"))
- || (args[1].equals("all")))
- {
- if (args.length == 2)
- {
- doList(args[1]);
- }
- else if (args.length == 3)
- {
- doList(args[1], args[2]);
- }
- }
- else
- {
- commandError("Unknown options. ", args);
- }
- }
- else if (args.length < 2)
- {
- doList("all");
- }
- else
- {
- doList(args[1]);
- }
- }
-
- private void doList(String... listItem)
- {
- if (_tool.getState().getVhost() == null)
- {
- _console.println("No Virtualhost open. Open a Virtualhost first.");
- listVirtualHosts();
- return;
- }
-
- VirtualHost vhost = _tool.getState().getVhost();
-
- java.util.List<String> data = null;
-
- if (listItem[0].equals("queues"))
- {
- if (listItem.length > 1)
- {
- data = listQueues(vhost, new AMQShortString(listItem[1]));
- }
- else
- {
- Exchange exchange = _tool.getState().getExchange();
- data = listQueues(vhost, exchange);
- }
- }
-
- if (listItem[0].equals("exchanges"))
- {
- data = listExchanges(vhost);
- }
-
- if (listItem[0].equals("bindings"))
- {
-
- if (listItem.length > 1)
- {
- data = listBindings(vhost, new AMQShortString(listItem[1]));
- }
- else
- {
- Exchange exchange = _tool.getState().getExchange();
-
- data = listBindings(vhost, exchange);
- }
- }
-
- if (data != null)
- {
- if (data.size() == 1)
- {
- _console.println("No '" + listItem[0] + "' to display,");
- }
- else
- {
- _console.displayList(true, data.toArray(new String[0]));
- }
- }
-
-
- if (listItem[0].equals("all"))
- {
-
- boolean displayed = false;
- Exchange exchange = _tool.getState().getExchange();
-
- //Do the display here for each one so that they are pretty printed
- data = listQueues(vhost, exchange);
- if (data != null)
- {
- displayed = true;
- _console.displayList(true, data.toArray(new String[0]));
- }
-
- if (exchange == null)
- {
- data = listExchanges(vhost);
- if (data != null)
- {
- displayed = true;
- _console.displayList(true, data.toArray(new String[0]));
- }
- }
-
- data = listBindings(vhost, exchange);
- if (data != null)
- {
- displayed = true;
- _console.displayList(true, data.toArray(new String[0]));
- }
-
- if (!displayed)
- {
- _console.println("Nothing to list");
- }
- }
- }
-
- private void listVirtualHosts()
- {
- Collection<VirtualHost> vhosts = ApplicationRegistry.getInstance()
- .getVirtualHostRegistry().getVirtualHosts();
-
- String[] data = new String[vhosts.size() + 1];
-
- data[0] = "Available VirtualHosts";
-
- int index = 1;
- for (VirtualHost vhost : vhosts)
- {
- data[index] = vhost.getName();
- index++;
- }
-
- _console.displayList(true, data);
- }
-
- private java.util.List<String> listBindings(VirtualHost vhost, AMQShortString exchangeName)
- {
- return listBindings(vhost, vhost.getExchangeRegistry().getExchange(exchangeName));
- }
-
- private java.util.List<String> listBindings(VirtualHost vhost, Exchange exchange)
- {
- Collection<AMQShortString> queues = vhost.getQueueRegistry().getQueueNames();
-
- if (queues == null || queues.size() == 0)
- {
- return null;
- }
-
- java.util.List<String> data = new LinkedList<String>();
-
- data.add("Current Bindings");
-
- for (AMQShortString queue : queues)
- {
- if (exchange != null)
- {
- if (exchange.isBound(queue))
- {
- data.add(queue.toString());
- }
- }
- else
- {
- data.add(queue.toString());
- }
- }
-
- return data;
- }
-
- private java.util.List<String> listExchanges(VirtualHost vhost)
- {
- Collection<AMQShortString> queues = vhost.getExchangeRegistry().getExchangeNames();
-
- if (queues == null || queues.size() == 0)
- {
- return null;
- }
-
- java.util.List<String> data = new LinkedList<String>();
-
- data.add("Available Exchanges");
-
- for (AMQShortString queue : queues)
- {
- data.add(queue.toString());
- }
-
- return data;
- }
-
- private java.util.List<String> listQueues(VirtualHost vhost, AMQShortString exchangeName)
- {
- return listQueues(vhost, vhost.getExchangeRegistry().getExchange(exchangeName));
- }
-
- private java.util.List<String> listQueues(VirtualHost vhost, Exchange exchange)
- {
- Collection<AMQQueue> queues = vhost.getQueueRegistry().getQueues();
-
- if (queues == null || queues.size() == 0)
- {
- return null;
- }
-
- java.util.List<String> data = new LinkedList<String>();
-
- data.add("Available Queues");
-
- for (AMQQueue queue : queues)
- {
- if (exchange != null)
- {
- if (exchange.isBound(queue))
- {
- data.add(queue.getNameShortString().toString());
- }
- }
- else
- {
- data.add(queue.getNameShortString().toString());
- }
- }
-
- if (exchange != null)
- {
- if (queues.size() == 1)
- {
- return null;
- }
- }
-
- return data;
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java
deleted file mode 100644
index 244a311c30..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Load.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.configuration.Configuration;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-public class Load extends AbstractCommand
-{
- public Load(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Loads specified broker configuration file.";
- }
-
- public String usage()
- {
- return "load <configuration file>";
- }
-
- public String getCommand()
- {
- return "load";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length > 2)
- {
- _console.print("load " + args[1] + ": additional options not understood:");
- for (int i = 2; i < args.length; i++)
- {
- _console.print(args[i] + " ");
- }
- _console.println("");
- }
- else if (args.length < 2)
- {
- _console.println("Enter Configuration file.");
- String input = _console.readln();
- if (input != null)
- {
- doLoad(input);
- }
- else
- {
- _console.println("Did not recognise config file.");
- }
- }
- else
- {
- doLoad(args[1]);
- }
- }
-
- private void doLoad(String configfile)
- {
- _console.println("Loading Configuration:" + configfile);
-
- try
- {
- _tool.setConfigurationFile(configfile);
- }
- catch (Configuration.InitException e)
- {
- _console.println("Unable to open config file due to: '" + e.getMessage() + "'");
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
deleted file mode 100644
index 615f6ec1c2..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.txn.ServerTransaction;
-import org.apache.qpid.server.txn.LocalTransaction;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class Move extends AbstractCommand
-{
-
- public Move(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Move messages between queues.";/*\n" +
- "The currently selected message set will be moved to the specifed queue.\n" +
- "Alternatively the values can be provided on the command line.";*/
- }
-
- public String usage()
- {
- return "move to=<queue> [from=<queue>] [msgids=<msgids eg, 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "move";
- }
-
- public void execute(String... args)
- {
- AMQQueue toQueue = null;
- AMQQueue fromQueue = _tool.getState().getQueue();
- java.util.List<Long> msgids = _tool.getState().getMessages();
-
- if (args.length >= 2)
- {
- for (String arg : args)
- {
- if (arg.startsWith("to="))
- {
- String queueName = arg.substring(arg.indexOf("=") + 1);
- toQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName));
- }
-
- if (arg.startsWith("from="))
- {
- String queueName = arg.substring(arg.indexOf("=") + 1);
- fromQueue = _tool.getState().getVhost().getQueueRegistry().getQueue(new AMQShortString(queueName));
- }
-
- if (arg.startsWith("msgids="))
- {
- String msgidStr = arg.substring(arg.indexOf("=") + 1);
-
- // Record the current message selection
- java.util.List<Long> currentIDs = _tool.getState().getMessages();
-
- // Use the ToolState class to perform the messasge parsing
- _tool.getState().setMessages(msgidStr);
- msgids = _tool.getState().getMessages();
-
- // Reset the original selection of messages
- _tool.getState().setMessages(currentIDs);
- }
- }
- }
-
- if (!checkRequirements(fromQueue, toQueue, msgids))
- {
- return;
- }
-
- processIDs(fromQueue, toQueue, msgids);
- }
-
- private void processIDs(AMQQueue fromQueue, AMQQueue toQueue, java.util.List<Long> msgids)
- {
- Long previous = null;
- Long start = null;
-
- if (msgids == null)
- {
- msgids = allMessageIDs(fromQueue);
- }
-
- if (msgids == null || msgids.size() == 0)
- {
- _console.println("No Messages to move.");
- return;
- }
-
- for (long id : msgids)
- {
- if (previous != null)
- {
- if (id == previous + 1)
- {
- if (start == null)
- {
- start = previous;
- }
- }
- else
- {
- if (start != null)
- {
- //move a range of ids
- doCommand(fromQueue, start, id, toQueue);
- start = null;
- }
- else
- {
- //move a single id
- doCommand(fromQueue, id, id, toQueue);
- }
- }
- }
-
- previous = id;
- }
-
- if (start != null)
- {
- //move a range of ids
- doCommand(fromQueue, start, previous, toQueue);
- }
- }
-
- private List<Long> allMessageIDs(AMQQueue fromQueue)
- {
- List<Long> ids = new LinkedList<Long>();
-
- if (fromQueue != null)
- {
- List<QueueEntry> messages = fromQueue.getMessagesOnTheQueue();
- if (messages != null)
- {
- for (QueueEntry msg : messages)
- {
- ids.add(msg.getMessage().getMessageNumber());
- }
- }
- }
-
- return ids;
- }
-
- protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, List<Long> msgids)
- {
- if (toQueue == null)
- {
- _console.println("Destination queue not specifed.");
- _console.println(usage());
- return false;
- }
-
- if (fromQueue == null)
- {
- _console.println("Source queue not specifed.");
- _console.println(usage());
- return false;
- }
-
- return true;
- }
-
- protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue)
- {
- ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog());
- fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getNameShortString().toString(), txn);
- txn.commit();
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
deleted file mode 100644
index 8df4afa2db..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.server.queue.AMQQueue;
-
-public class Purge extends Move
-{
- public Purge(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Purge messages from a queue.\n" +
- "The currently selected message set will be purged from the specifed queue.\n" +
- "Alternatively the values can be provided on the command line.";
- }
-
- public String usage()
- {
- return "purge from=<queue> [msgids=<msgids eg, 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "purge";
- }
-
-
- protected boolean checkRequirements(AMQQueue fromQueue, AMQQueue toQueue, java.util.List<Long> msgids)
- {
- if (fromQueue == null)
- {
- _console.println("Source queue not specifed.");
- _console.println(usage());
- return false;
- }
-
- return true;
- }
-
- protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue)
- {
- fromQueue.removeMessagesFromQueue(start, end);
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java
deleted file mode 100644
index a81bc07c38..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Quit.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-public class Quit extends AbstractCommand
-{
- public Quit(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Quit the tool.";
- }
-
- public String usage()
- {
- return "quit";
- }
-
- public String getCommand()
- {
- return "quit";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals("quit");
-
- _tool.quit();
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
deleted file mode 100644
index ff59568374..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Select.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-
-import java.util.LinkedList;
-import java.util.StringTokenizer;
-
-public class Select extends AbstractCommand
-{
-
- public Select(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Perform a selection.";
- }
-
- public String usage()
- {
- return "select virtualhost <name> |exchange <name> |queue <name> | msg id=<msgids eg. 1,2,4-10>";
- }
-
- public String getCommand()
- {
- return "select";
- }
-
- public void execute(String... args)
- {
- assert args.length > 2;
- assert args[0].equals("select");
-
- if (args.length < 3)
- {
- if (args[1].equals("show"))
- {
- doSelect(args[1], null);
- }
- else
- {
- _console.print("select : unknown command:");
- _console.println(help());
- }
- }
- else
- {
- if (args[1].equals("virtualhost")
- || args[1].equals("vhost")
- || args[1].equals("exchange")
- || args[1].equals("queue")
- || args[1].equals("msg")
- )
- {
- doSelect(args[1], args[2]);
- }
- else
- {
- _console.println(help());
- }
- }
- }
-
- private void doSelect(String type, String item)
- {
- if (type.equals("virtualhost"))
- {
-
- VirtualHost vhost = ApplicationRegistry.getInstance()
- .getVirtualHostRegistry().getVirtualHost(item);
-
- if (vhost == null)
- {
- _console.println("Virtualhost '" + item + "' not found.");
- }
- else
- {
- _tool.getState().setVhost(vhost);
- }
- }
-
- if (type.equals("exchange"))
- {
-
- VirtualHost vhost = _tool.getState().getVhost();
-
- if (vhost == null)
- {
- _console.println("No Virtualhost open. Open a Virtualhost first.");
- return;
- }
-
-
- Exchange exchange = vhost.getExchangeRegistry().getExchange(new AMQShortString(item));
-
- if (exchange == null)
- {
- _console.println("Exchange '" + item + "' not found.");
- }
- else
- {
- _tool.getState().setExchange(exchange);
- }
-
- if (_tool.getState().getQueue() != null)
- {
- if (!exchange.isBound(_tool.getState().getQueue()))
- {
- _tool.getState().setQueue(null);
- }
- }
- }
-
- if (type.equals("queue"))
- {
- VirtualHost vhost = _tool.getState().getVhost();
-
- if (vhost == null)
- {
- _console.println("No Virtualhost open. Open a Virtualhost first.");
- return;
- }
-
- AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(item));
-
- if (queue == null)
- {
- _console.println("Queue '" + item + "' not found.");
- }
- else
- {
- _tool.getState().setQueue(queue);
-
- if (_tool.getState().getExchange() == null)
- {
- for (AMQShortString exchangeName : vhost.getExchangeRegistry().getExchangeNames())
- {
- Exchange exchange = vhost.getExchangeRegistry().getExchange(exchangeName);
- if (exchange.isBound(queue))
- {
- _tool.getState().setExchange(exchange);
- break;
- }
- }
- }
-
- //remove the message selection
- _tool.getState().setMessages((java.util.List<Long>) null);
- }
- }
-
- if (type.equals("msg"))
- {
- if (item.startsWith("id="))
- {
- StringTokenizer tok = new StringTokenizer(item.substring(item.indexOf("=") + 1), ",");
-
- java.util.List<Long> msgids = null;
-
- if (tok.hasMoreTokens())
- {
- msgids = new LinkedList<Long>();
- }
-
- while (tok.hasMoreTokens())
- {
- String next = tok.nextToken();
- if (next.contains("-"))
- {
- Long start = Long.parseLong(next.substring(0, next.indexOf("-")));
- Long end = Long.parseLong(next.substring(next.indexOf("-") + 1));
-
- if (end >= start)
- {
- for (long l = start; l <= end; l++)
- {
- msgids.add(l);
- }
- }
- }
- else
- {
- msgids.add(Long.parseLong(next));
- }
- }
-
- _tool.getState().setMessages(msgids);
- }
-
- }
-
- if (type.equals("show"))
- {
- _console.println(_tool.getState().toString());
- if (_tool.getState().getMessages() != null)
- {
- _console.print("Msgs:");
- for (Long l : _tool.getState().getMessages())
- {
- _console.print(" " + l);
- }
- _console.println("");
- }
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
deleted file mode 100644
index 806e161bbc..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.messagestore.commands;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.message.AMQMessage;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.tools.messagestore.MessageStoreTool;
-import org.apache.qpid.tools.utils.Console;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class Show extends AbstractCommand
-{
- protected boolean _amqHeaders = false;
- protected boolean _routing = false;
- protected boolean _msgHeaders = false;
-
- public Show(MessageStoreTool tool)
- {
- super(tool);
- }
-
- public String help()
- {
- return "Shows the messages headers.";
- }
-
- public String usage()
- {
- return getCommand() + " [show=[all],[msgheaders],[amqheaders],[routing]] [id=<msgid e.g. 1,2,4-10>]";
- }
-
- public String getCommand()
- {
- return "show";
- }
-
- public void execute(String... args)
- {
- assert args.length > 0;
- assert args[0].equals(getCommand());
-
- if (args.length < 2)
- {
- parseArgs("all");
- }
- else
- {
- parseArgs(args);
- }
-
- performShow();
- }
-
- protected void parseArgs(String... args)
- {
- List<Long> msgids = null;
-
- if (args.length >= 2)
- {
- for (String arg : args)
- {
- if (arg.startsWith("show="))
- {
- _msgHeaders = arg.contains("msgheaders") || arg.contains("all");
- _amqHeaders = arg.contains("amqheaders") || arg.contains("all");
- _routing = arg.contains("routing") || arg.contains("all");
- }
-
- if (arg.startsWith("id="))
- {
- _tool.getState().setMessages(msgids);
- }
- }//for args
- }// if args > 2
- }
-
- protected void performShow()
- {
- if (_tool.getState().getVhost() == null)
- {
- _console.println("No Virtualhost selected. 'DuSelect' a Virtualhost first.");
- return;
- }
-
- AMQQueue _queue = _tool.getState().getQueue();
-
- List<Long> msgids = _tool.getState().getMessages();
-
- if (_queue != null)
- {
- List<QueueEntry> messages = _queue.getMessagesOnTheQueue();
- if (messages == null || messages.size() == 0)
- {
- _console.println("No messages on queue");
- return;
- }
-
- List<List> data = createMessageData(msgids, messages, _amqHeaders, _routing, _msgHeaders);
- if (data != null)
- {
- _console.printMap(null, data);
- }
- else
- {
- String message = "No data to display.";
- if (msgids != null)
- {
- message += " Is message selection correct? " + _tool.getState().printMessages();
- }
- _console.println(message);
- }
-
- }
- else
- {
- _console.println("No Queue specified to show.");
- }
- }
-
- /**
- * Create the list data for display from the messages.
- *
- * @param msgids The list of message ids to display
- * @param messages A list of messages to format and display.
- * @param showHeaders should the header info be shown
- * @param showRouting show the routing info be shown
- * @param showMessageHeaders show the msg headers be shown
- * @return the formated data lists for printing
- */
- protected List<List> createMessageData(List<Long> msgids, List<QueueEntry> messages, boolean showHeaders, boolean showRouting,
- boolean showMessageHeaders)
- {
-
- // Currenly exposed message properties
-// //Printing the content Body
-// msg.getContentBodyIterator();
-// //Print the Headers
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppId();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getAppIdAsString();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getClusterId();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getContentType();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getCorrelationId();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getDeliveryMode();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageNumber();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getTimestamp();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getType();
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getUserId();
-//
-// //Print out all the property names
-// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames();
-//
-// msg.getMessageNumber();
-// msg.getSize();
-// msg.getArrivalTime();
-
-// msg.getDeliveredSubscription();
-// msg.getDeliveredToConsumer();
-// msg.getMessageHandle();
-// msg.getMessageNumber();
-// msg.getMessagePublishInfo();
-// msg.getPublisher();
-
-// msg.getStoreContext();
-// msg.isAllContentReceived();
-// msg.isPersistent();
-// msg.isRedelivered();
-// msg.isRejectedBy();
-// msg.isTaken();
-
- //Header setup
-
- List<List> data = new LinkedList<List>();
-
- List<String> id = new LinkedList<String>();
- data.add(id);
- id.add(Columns.ID.name());
- id.add(Console.ROW_DIVIDER);
-
- List<String> exchange = new LinkedList<String>();
- List<String> routingkey = new LinkedList<String>();
- List<String> immediate = new LinkedList<String>();
- List<String> mandatory = new LinkedList<String>();
- if (showRouting)
- {
- data.add(exchange);
- exchange.add(Columns.Exchange.name());
- exchange.add(Console.ROW_DIVIDER);
-
- data.add(routingkey);
- routingkey.add(Columns.RoutingKey.name());
- routingkey.add(Console.ROW_DIVIDER);
-
- data.add(immediate);
- immediate.add(Columns.isImmediate.name());
- immediate.add(Console.ROW_DIVIDER);
-
- data.add(mandatory);
- mandatory.add(Columns.isMandatory.name());
- mandatory.add(Console.ROW_DIVIDER);
- }
-
- List<String> size = new LinkedList<String>();
- List<String> appid = new LinkedList<String>();
- List<String> clusterid = new LinkedList<String>();
- List<String> contenttype = new LinkedList<String>();
- List<String> correlationid = new LinkedList<String>();
- List<String> deliverymode = new LinkedList<String>();
- List<String> encoding = new LinkedList<String>();
- List<String> arrival = new LinkedList<String>();
- List<String> expiration = new LinkedList<String>();
- List<String> priority = new LinkedList<String>();
- List<String> propertyflag = new LinkedList<String>();
- List<String> replyto = new LinkedList<String>();
- List<String> timestamp = new LinkedList<String>();
- List<String> type = new LinkedList<String>();
- List<String> userid = new LinkedList<String>();
- List<String> ispersitent = new LinkedList<String>();
- List<String> isredelivered = new LinkedList<String>();
- List<String> isdelivered = new LinkedList<String>();
-
- data.add(size);
- size.add(Columns.Size.name());
- size.add(Console.ROW_DIVIDER);
-
- if (showHeaders)
- {
- data.add(ispersitent);
- ispersitent.add(Columns.isPersistent.name());
- ispersitent.add(Console.ROW_DIVIDER);
-
- data.add(isredelivered);
- isredelivered.add(Columns.isRedelivered.name());
- isredelivered.add(Console.ROW_DIVIDER);
-
- data.add(isdelivered);
- isdelivered.add(Columns.isDelivered.name());
- isdelivered.add(Console.ROW_DIVIDER);
-
- data.add(appid);
- appid.add(Columns.App_ID.name());
- appid.add(Console.ROW_DIVIDER);
-
- data.add(clusterid);
- clusterid.add(Columns.Cluster_ID.name());
- clusterid.add(Console.ROW_DIVIDER);
-
- data.add(contenttype);
- contenttype.add(Columns.Content_Type.name());
- contenttype.add(Console.ROW_DIVIDER);
-
- data.add(correlationid);
- correlationid.add(Columns.Correlation_ID.name());
- correlationid.add(Console.ROW_DIVIDER);
-
- data.add(deliverymode);
- deliverymode.add(Columns.Delivery_Mode.name());
- deliverymode.add(Console.ROW_DIVIDER);
-
- data.add(encoding);
- encoding.add(Columns.Encoding.name());
- encoding.add(Console.ROW_DIVIDER);
-
- data.add(arrival);
- expiration.add(Columns.Arrival.name());
- expiration.add(Console.ROW_DIVIDER);
-
- data.add(expiration);
- expiration.add(Columns.Expiration.name());
- expiration.add(Console.ROW_DIVIDER);
-
- data.add(priority);
- priority.add(Columns.Priority.name());
- priority.add(Console.ROW_DIVIDER);
-
- data.add(propertyflag);
- propertyflag.add(Columns.Property_Flag.name());
- propertyflag.add(Console.ROW_DIVIDER);
-
- data.add(replyto);
- replyto.add(Columns.ReplyTo.name());
- replyto.add(Console.ROW_DIVIDER);
-
- data.add(timestamp);
- timestamp.add(Columns.Timestamp.name());
- timestamp.add(Console.ROW_DIVIDER);
-
- data.add(type);
- type.add(Columns.Type.name());
- type.add(Console.ROW_DIVIDER);
-
- data.add(userid);
- userid.add(Columns.UserID.name());
- userid.add(Console.ROW_DIVIDER);
- }
-
- List<String> msgHeaders = new LinkedList<String>();
- if (showMessageHeaders)
- {
- data.add(msgHeaders);
- msgHeaders.add(Columns.MsgHeaders.name());
- msgHeaders.add(Console.ROW_DIVIDER);
- }
-
- //Add create the table of data
- for (QueueEntry entry : messages)
- {
- ServerMessage msg = entry.getMessage();
- if (!includeMsg(msg, msgids))
- {
- continue;
- }
-
- id.add(msg.getMessageNumber().toString());
-
- size.add("" + msg.getSize());
-
- arrival.add("" + msg.getArrivalTime());
-
- ispersitent.add(msg.isPersistent() ? "true" : "false");
-
-
- isredelivered.add(entry.isRedelivered() ? "true" : "false");
-
- isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false");
-
-// msg.getMessageHandle();
-
- BasicContentHeaderProperties headers = null;
-
- try
- {
- if(msg instanceof AMQMessage)
- {
- headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().getProperties());
- }
- }
- catch (AMQException e)
- {
- //ignore
-// commandError("Unable to read properties for message: " + e.getMessage(), null);
- }
-
- if (headers != null)
- {
- String appidS = headers.getAppIdAsString();
- appid.add(appidS == null ? "null" : appidS);
-
- String clusterS = headers.getClusterIdAsString();
- clusterid.add(clusterS == null ? "null" : clusterS);
-
- String contentS = headers.getContentTypeAsString();
- contenttype.add(contentS == null ? "null" : contentS);
-
- String correlationS = headers.getCorrelationIdAsString();
- correlationid.add(correlationS == null ? "null" : correlationS);
-
- deliverymode.add("" + headers.getDeliveryMode());
-
- AMQShortString encodeSS = headers.getEncoding();
- encoding.add(encodeSS == null ? "null" : encodeSS.toString());
-
- expiration.add("" + headers.getExpiration());
-
- FieldTable headerFT = headers.getHeaders();
- msgHeaders.add(headerFT == null ? "none" : "" + headerFT.toString());
-
- priority.add("" + headers.getPriority());
- propertyflag.add("" + headers.getPropertyFlags());
-
- AMQShortString replytoSS = headers.getReplyTo();
- replyto.add(replytoSS == null ? "null" : replytoSS.toString());
-
- timestamp.add("" + headers.getTimestamp());
-
- AMQShortString typeSS = headers.getType();
- type.add(typeSS == null ? "null" : typeSS.toString());
-
- AMQShortString useridSS = headers.getUserId();
- userid.add(useridSS == null ? "null" : useridSS.toString());
-
- MessagePublishInfo info = null;
- try
- {
- if(msg instanceof AMQMessage)
- {
- info = ((AMQMessage)msg).getMessagePublishInfo();
- }
-
- }
- catch (AMQException e)
- {
- //ignore
- }
-
- if (info != null)
- {
- AMQShortString exchangeSS = info.getExchange();
- exchange.add(exchangeSS == null ? "null" : exchangeSS.toString());
-
- AMQShortString routingkeySS = info.getRoutingKey();
- routingkey.add(routingkeySS == null ? "null" : routingkeySS.toString());
-
- immediate.add(info.isImmediate() ? "true" : "false");
- mandatory.add(info.isMandatory() ? "true" : "false");
- }
-
-// msg.getPublisher(); -- only used in clustering
-// msg.getStoreContext();
-// msg.isAllContentReceived();
-
- }// if headers!=null
-
-// need to access internal map and do lookups.
-// msg.isTaken();
-// msg.getDeliveredSubscription();
-// msg.isRejectedBy();
-
- }
-
- // if id only had the header and the divider in it then we have no data to display
- if (id.size() == 2)
- {
- return null;
- }
- return data;
- }
-
- protected boolean includeMsg(ServerMessage msg, List<Long> msgids)
- {
- if (msgids == null)
- {
- return true;
- }
-
- Long msgid = msg.getMessageNumber();
-
- boolean found = false;
-
- if (msgids != null)
- {
- //check msgid is in msgids
- for (Long l : msgids)
- {
- if (l.equals(msgid))
- {
- found = true;
- break;
- }
- }
- }
- return found;
- }
-
- public enum Columns
- {
- ID,
- Size,
- Exchange,
- RoutingKey,
- isImmediate,
- isMandatory,
- isPersistent,
- isRedelivered,
- isDelivered,
- App_ID,
- Cluster_ID,
- Content_Type,
- Correlation_ID,
- Delivery_Mode,
- Encoding,
- Arrival,
- Expiration,
- Priority,
- Property_Flag,
- ReplyTo,
- Timestamp,
- Type,
- UserID,
- MsgHeaders
- }
-}
-
-
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
index c27c52eb8e..bfcdbe7460 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
@@ -60,9 +60,6 @@ public class Passwd
private static void output(String user, byte[] encoded) throws IOException
{
-
-// File passwdFile = new File("qpid.passwd");
-
PrintStream ps = new PrintStream(System.out);
user += ":";
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java
deleted file mode 100644
index 986fea32cc..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/CommandParser.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.utils;
-
-public interface CommandParser
-{
- /**
- * If there is more than one command received on the last parse request.
- *
- * Subsequent calls to parse will utilise this input rather than reading new data from the input source
- * @return boolean
- */
- boolean more();
-
- /**
- * True if the currently parsed command has been requested as a background operation
- *
- * @return boolean
- */
- boolean isBackground();
-
- /**
- * Parses user commands, and groups tokens in the
- * String[] format that all Java main's love.
- *
- * If more than one command is provided in one input line then the more() method will return true.
- * A subsequent call to parse() will continue to parse that input line before reading new input.
- *
- * @return <code>input</code> split in args[] format; null if eof.
- * @throws java.io.IOException if there is a problem reading from the input stream
- */
- String[] parse() throws java.io.IOException;
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java
deleted file mode 100644
index cf457d1ea5..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/Console.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.utils;
-
-import java.util.List;
-
-public interface Console
-{
- public enum CellFormat
- {
- CENTRED, LEFT, RIGHT
- }
-
- public static String ROW_DIVIDER = "*divider";
-
- public void print(String... message);
-
- public void println(String... message);
-
- public String readln();
-
- /**
- * Reads and parses the command line.
- *
- *
- * @return The next command or null
- */
- public String[] readCommand();
-
- public CommandParser getCommandParser();
-
- public void setCommandParser(CommandParser parser);
-
- /**
- *
- * Prints the list of String nicely.
- *
- * +-------------+
- * | Heading |
- * +-------------+
- * | Item 1 |
- * | Item 2 |
- * | Item 3 |
- * +-------------+
- *
- * @param hasTitle should list[0] be used as a heading
- * @param list The list of Strings to display
- */
- public void displayList(boolean hasTitle, String... list);
-
- /**
- *
- * Prints the list of String nicely.
- *
- * +----------------------------+
- * | Heading |
- * +----------------------------+
- * | title | title | ..
- * +----------------------------+
- * | Item 2 | value 2 | ..
- * +----------------------------+ (*divider)
- * | Item 3 | value 2 | ..
- * +----------------------------+
- *
- * @param title The title to display if any
- * @param entries the entries to display in a map.
- */
- void printMap(String title, List<List> entries);
-
-
- public void close();
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java
deleted file mode 100644
index 09444ccdd7..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleCommandParser.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.utils;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.util.StringTokenizer;
-
-public class SimpleCommandParser implements CommandParser
-{
- private static final String COMMAND_SEPERATOR = ";";
-
- /** Input source of commands */
- protected BufferedReader _reader;
-
- /** The next list of commands from the command line */
- private StringBuilder _nextCommand = null;
-
- public SimpleCommandParser(BufferedReader reader)
- {
- _reader = reader;
- }
-
- public boolean more()
- {
- return _nextCommand != null;
- }
-
- public boolean isBackground()
- {
- return false;
- }
-
- public String[] parse() throws IOException
- {
- String[] commands = null;
-
- String input = null;
-
- if (_nextCommand == null)
- {
- input = _reader.readLine();
- }
- else
- {
- input = _nextCommand.toString();
- _nextCommand = null;
- }
-
- if (input == null)
- {
- return null;
- }
-
- StringTokenizer tok = new StringTokenizer(input, " ");
-
- int tokenCount = tok.countTokens();
- int index = 0;
-
- if (tokenCount > 0)
- {
- commands = new String[tokenCount];
- boolean commandComplete = false;
-
- while (tok.hasMoreTokens())
- {
- String next = tok.nextToken();
-
- if (next.equals(COMMAND_SEPERATOR))
- {
- commandComplete = true;
- _nextCommand = new StringBuilder();
- continue;
- }
-
- if (commandComplete)
- {
- _nextCommand.append(next);
- _nextCommand.append(" ");
- }
- else
- {
- commands[index] = next;
- index++;
- }
- }
-
- }
-
- //Reduce the String[] if not all the tokens were used in this command.
- // i.e. there is more than one command on the line.
- if (index != tokenCount)
- {
- String[] shortCommands = new String[index];
- System.arraycopy(commands, 0, shortCommands, 0, index);
- return shortCommands;
- }
- else
- {
- return commands;
- }
- }
-}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java
deleted file mode 100644
index 2791a39f92..0000000000
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/utils/SimpleConsole.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.tools.utils;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-public class SimpleConsole implements Console
-{
- /** SLF4J Logger. */
- private static Logger _devlog = LoggerFactory.getLogger(SimpleConsole.class);
-
- /** Console Writer. */
- protected BufferedWriter _consoleWriter;
-
- /** Console Reader. */
- protected BufferedReader _consoleReader;
-
- /** Parser for command-line input. */
- protected CommandParser _parser;
-
- public SimpleConsole(BufferedWriter writer, BufferedReader reader)
- {
- _consoleWriter = writer;
- _consoleReader = reader;
- _parser = new SimpleCommandParser(_consoleReader);
- }
-
- public void print(String... message)
- {
- try
- {
- for (String s : message)
- {
- _consoleWriter.write(s);
- }
- _consoleWriter.flush();
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occurred whilst trying to write:" + Arrays.asList(message));
- }
-
- }
-
- public void println(String... message)
- {
- print(message);
- print(System.getProperty("line.separator"));
- }
-
-
- public String readln()
- {
- try
- {
- return _consoleReader.readLine();
- }
- catch (IOException e)
- {
- _devlog.debug("Unable to read input due to:" + e.getMessage());
- return null;
- }
- }
-
- public String[] readCommand()
- {
- try
- {
- return _parser.parse();
- }
- catch (IOException e)
- {
- _devlog.error("Error reading command:" + e.getMessage());
- return new String[0];
- }
- }
-
- public CommandParser getCommandParser()
- {
- return _parser;
- }
-
- public void setCommandParser(CommandParser parser)
- {
- _parser = parser;
- }
-
- public void displayList(boolean hasTitle, String... list)
- {
- java.util.List<java.util.List> data = new LinkedList<List>();
-
- java.util.List<String> values = new LinkedList<String>();
-
- data.add(values);
-
- for (String value : list)
- {
- values.add(value);
- }
-
- if (hasTitle)
- {
- values.add(1, "*divider");
- }
-
- printMap(null, data);
- }
-
- /**
- *
- * Prints the list of String nicely.
- *
- * +----------------------------+
- * | Heading |
- * +----------------------------+
- * | title | title | ..
- * +----------------------------+
- * | Item 2 | value 2 | ..
- * | Item 3 | value 2 | ..
- * +----------------------------+
- *
- * @param title The title to display if any
- * @param entries the entries to display in a map.
- */
- public void printMap(String title, java.util.List<java.util.List> entries)
- {
- try
- {
- int columns = entries.size();
-
- int[] columnWidth = new int[columns];
-
- // calculate row count
- int rowMax = 0;
-
- //the longest item
- int itemMax = 0;
-
- for (int i = 0; i < columns; i++)
- {
- int columnIRowMax = entries.get(i).size();
-
- if (columnIRowMax > rowMax)
- {
- rowMax = columnIRowMax;
- }
- for (Object values : entries.get(i))
- {
- if (values.toString().equals(Console.ROW_DIVIDER))
- {
- continue;
- }
-
- int itemLength = values.toString().length();
-
- //note for single width
- if (itemLength > itemMax)
- {
- itemMax = itemLength;
- }
-
- //note for mulit width
- if (itemLength > columnWidth[i])
- {
- columnWidth[i] = itemLength;
- }
-
- }
- }
-
- int tableWidth = 0;
-
-
- for (int i = 0; i < columns; i++)
- {
- // plus 2 for the space padding
- columnWidth[i] += 2;
- }
- for (int size : columnWidth)
- {
- tableWidth += size;
- }
- tableWidth += (columns - 1);
-
- if (title != null)
- {
- if (title.length() > tableWidth)
- {
- tableWidth = title.length();
- }
-
- printCellRow("+", "-", tableWidth);
-
- printCell(CellFormat.CENTRED, "|", tableWidth, " " + title + " ", 0);
- _consoleWriter.newLine();
-
- }
-
- //put top line | or bottom of title
- printCellRow("+", "-", tableWidth);
-
- //print the table data
- int row = 0;
-
- for (; row < rowMax; row++)
- {
- for (int i = 0; i < columns; i++)
- {
- java.util.List columnData = entries.get(i);
-
- String value;
- // does this column have a value for this row
- if (columnData.size() > row)
- {
- value = " " + columnData.get(row).toString() + " ";
- }
- else
- {
- value = " ";
- }
-
- if (i == 0 && value.equals(" " + Console.ROW_DIVIDER + " "))
- {
- printCellRow("+", "-", tableWidth);
- //move on to the next row
- break;
- }
- else
- {
- printCell(CellFormat.LEFT, "|", columnWidth[i], value, i);
- }
-
- // if it is the last row then do a new line.
- if (i == columns - 1)
- {
- _consoleWriter.newLine();
- }
- }
- }
-
- printCellRow("+", "-", tableWidth);
-
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occured whilst trying to write.");
- }
- }
-
- public void close()
- {
-
- try
- {
- _consoleReader.close();
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occured whilst trying to close reader.");
- }
-
- try
- {
-
- _consoleWriter.close();
- }
- catch (IOException e)
- {
- _devlog.error(e.getMessage() + ": Occured whilst trying to close writer.");
- }
-
- }
-
- private void printCell(CellFormat format, String edge, int cellWidth, String cell, int column) throws IOException
- {
- int pad = cellWidth - cell.length();
-
- if (column == 0)
- {
- _consoleWriter.write(edge);
- }
-
- switch (format)
- {
- case CENTRED:
- printPad(" ", pad / 2);
- break;
- case RIGHT:
- printPad(" ", pad);
- break;
- }
-
- _consoleWriter.write(cell);
-
-
- switch (format)
- {
- case CENTRED:
- // if pad isn't even put the extra one on the right
- if (pad % 2 == 0)
- {
- printPad(" ", pad / 2);
- }
- else
- {
- printPad(" ", (pad / 2) + 1);
- }
- break;
- case LEFT:
- printPad(" ", pad);
- break;
- }
-
-
- _consoleWriter.write(edge);
-
- }
-
- private void printCellRow(String edge, String mid, int cellWidth) throws IOException
- {
- _consoleWriter.write(edge);
-
- printPad(mid, cellWidth);
-
- _consoleWriter.write(edge);
- _consoleWriter.newLine();
- }
-
- private void printPad(String padChar, int count) throws IOException
- {
- for (int i = 0; i < count; i++)
- {
- _consoleWriter.write(padChar);
- }
- }
-
-
-}