diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2009-10-25 22:58:57 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2009-10-25 22:58:57 +0000 |
commit | afcf8099695253651c73910a243fb29aa520b008 (patch) | |
tree | e514bc51797181c567500a8ddbfc20ea9b89b908 | |
parent | f315ac548e346ded9ed1d081db4118e703c362b4 (diff) | |
download | qpid-python-afcf8099695253651c73910a243fb29aa520b008.tar.gz |
Merged from java-broker-0-10 branch
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@829675 13f79535-47bb-0310-9956-ffa450edef68
266 files changed, 13270 insertions, 8185 deletions
diff --git a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java index aa64fab6cd..637997a947 100644 --- a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java +++ b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchange.java @@ -20,10 +20,8 @@ */ package org.apache.qpid.extras.exchanges.diagnostic; -import java.util.List; -import java.util.Map; import java.util.ArrayList; -import java.util.Collection; +import java.util.Map; import javax.management.JMException; import javax.management.openmbean.OpenDataException; @@ -34,27 +32,31 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.AbstractExchange; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.junit.extensions.util.SizeOf; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.log4j.Logger; /** - * + * * This is a special diagnostic exchange type which doesn't actually do anything * with messages. When it receives a message, it writes information about the * current memory usage to the "memory" property of the message and places it on the - * diagnosticqueue for retrieval - * + * diagnosticqueue for retrieval + * * @author Aidan Skinner - * + * */ public class DiagnosticExchange extends AbstractExchange { - + + private static final Logger _logger = Logger.getLogger(DiagnosticExchange.class); + + public static final AMQShortString DIAGNOSTIC_EXCHANGE_CLASS = new AMQShortString("x-diagnostic"); public static final AMQShortString DIAGNOSTIC_EXCHANGE_NAME = new AMQShortString("diagnostic"); @@ -72,7 +74,7 @@ public class DiagnosticExchange extends AbstractExchange /** * Usual constructor. - * + * * @throws JMException */ @MBeanConstructor("Creates an MBean for AMQ Diagnostic exchange") @@ -85,7 +87,7 @@ public class DiagnosticExchange extends AbstractExchange /** * Returns nothing, there can be no tabular data for this... - * + * * @throws OpenDataException * @returns null * @todo ... or can there? Could this actually return all the @@ -99,7 +101,7 @@ public class DiagnosticExchange extends AbstractExchange /** * This exchange type doesn't support queues, so this method does * nothing. - * + * * @param queueName * the queue you'll fail to create * @param binding @@ -116,22 +118,20 @@ public class DiagnosticExchange extends AbstractExchange /** * Creates a new MBean instance - * + * * @return the newly created MBean * @throws AMQException * if something goes wrong */ - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new DiagnosticExchange.DiagnosticExchangeMBean(); - } - catch (JMException ex) - { - // _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException(null, "Exception occured in creating the direct exchange mbean", ex); - } + return new DiagnosticExchange.DiagnosticExchangeMBean(); + + } + + public Logger getLogger() + { + return _logger; } public AMQShortString getType() @@ -141,7 +141,7 @@ public class DiagnosticExchange extends AbstractExchange /** * Does nothing. - * + * * @param routingKey * pointless * @param queue @@ -156,9 +156,15 @@ public class DiagnosticExchange extends AbstractExchange // No op } + public void registerQueue(String routingKey, AMQQueue queue, Map<String, Object> args) throws AMQException + { + // No op + } + + /** * Does nothing. - * + * * @param routingKey * pointless * @param queue @@ -193,27 +199,29 @@ public class DiagnosticExchange extends AbstractExchange return false; } - public void route(IncomingMessage payload) throws AMQException + public ArrayList<AMQQueue> route(InboundMessage payload) { - + Long value = new Long(SizeOf.getUsedMemory()); AMQShortString key = new AMQShortString("memory"); - - FieldTable headers = ((BasicContentHeaderProperties)payload.getContentHeaderBody().properties).getHeaders(); + + //TODO shouldn't modify messages... perhaps put a new message on the queue? +/* FieldTable headers = ((BasicContentHeaderProperties)payload.getMessageHeader().properties).getHeaders(); headers.put(key, value); - ((BasicContentHeaderProperties)payload.getContentHeaderBody().properties).setHeaders(headers); + ((BasicContentHeaderProperties)payload.getMessageHeader().properties).setHeaders(headers);*/ AMQQueue q = getQueueRegistry().getQueue(new AMQShortString("diagnosticqueue")); ArrayList<AMQQueue> queues = new ArrayList<AMQQueue>(); queues.add(q); - payload.enqueue(queues); - + return queues; + } - + public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) { // TODO Auto-generated method stub return false; } + } diff --git a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java index d96b4dc99e..b4d0d1aa0d 100644 --- a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java +++ b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/diagnostic/DiagnosticExchangeType.java @@ -31,7 +31,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; */ public final class DiagnosticExchangeType implements ExchangeType<DiagnosticExchange> { - + public AMQShortString getName() { return DiagnosticExchange.DIAGNOSTIC_EXCHANGE_CLASS; diff --git a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java index e43bd2ddc0..cb46b9c815 100644 --- a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java +++ b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchange.java @@ -1,6 +1,6 @@ package org.apache.qpid.extras.exchanges.example; /* - * + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -8,29 +8,31 @@ package org.apache.qpid.extras.exchanges.example; * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * + * */ import java.util.List; import java.util.Map; +import java.util.ArrayList; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.IncomingMessage; +import org.apache.qpid.server.exchange.ExchangeReferrer; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; public class TestExchange implements Exchange { @@ -63,6 +65,41 @@ public class TestExchange implements Exchange return false; } + public boolean isBound(String bindingKey, AMQQueue queue) + { + return false; + } + + public boolean isBound(String bindingKey) + { + return false; + } + + public Exchange getAlternateExchange() + { + return null; + } + + public void setAlternateExchange(Exchange exchange) + { + + } + + public void removeReference(ExchangeReferrer exchange) + { + + } + + public void addReference(ExchangeReferrer exchange) + { + + } + + public boolean hasReferrers() + { + return false; + } + public void initialise(VirtualHost host, AMQShortString name, boolean durable, boolean autoDelete) throws AMQException { @@ -102,8 +139,9 @@ public class TestExchange implements Exchange { } - public void route(IncomingMessage message) throws AMQException + public ArrayList<AMQQueue> route(InboundMessage message) { + return new ArrayList<AMQQueue>(); } public int getTicket() diff --git a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java index 22833693ca..db02ca13ea 100644 --- a/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java +++ b/qpid/java/broker-plugins/src/main/java/org/apache/qpid/extras/exchanges/example/TestExchangeType.java @@ -40,7 +40,7 @@ public class TestExchangeType implements ExchangeType return null; } - public Exchange newInstance(VirtualHost host, AMQShortString name, boolean durable, + public Exchange newInstance(VirtualHost host, AMQShortString name, boolean durable, int token, boolean autoDelete) throws AMQException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index 5cfa8066e5..08b3c08215 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -63,8 +63,9 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.AMQQueueMBean; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -78,12 +79,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr private final QueueRegistry _queueRegistry; private final ExchangeRegistry _exchangeRegistry; private final ExchangeFactory _exchangeFactory; - private final MessageStore _messageStore; + private final DurableConfigurationStore _durableConfig; - private final VirtualHost.VirtualHostMBean _virtualHostMBean; + private final VirtualHostImpl.VirtualHostMBean _virtualHostMBean; @MBeanConstructor("Creates the Broker Manager MBean") - public AMQBrokerManagerMBean(VirtualHost.VirtualHostMBean virtualHostMBean) throws JMException + public AMQBrokerManagerMBean(VirtualHostImpl.VirtualHostMBean virtualHostMBean) throws JMException { super(ManagedBroker.class, ManagedBroker.TYPE, ManagedBroker.VERSION); @@ -92,7 +93,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr _queueRegistry = virtualHost.getQueueRegistry(); _exchangeRegistry = virtualHost.getExchangeRegistry(); - _messageStore = virtualHost.getMessageStore(); + _durableConfig = virtualHost.getDurableConfigurationStore(); _exchangeFactory = virtualHost.getExchangeFactory(); } @@ -113,10 +114,10 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { exchangeTypes.add(ex.getName().toString()); } - + return exchangeTypes.toArray(new String[0]); } - + /** * Returns a list containing the names of the attributes available for the Queue mbeans. * @since Qpid JMX API 1.3 @@ -129,12 +130,12 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { attributeList.add(attr); } - + Collections.sort(attributeList); return attributeList; } - + /** * Returns a List of Object Lists containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost. * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-". @@ -147,22 +148,22 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { return new ArrayList<List<Object>>(); } - + List<List<Object>> queueAttributesList = new ArrayList<List<Object>>(_queueRegistry.getQueues().size()); - + int attributesLength = attributes.length; - + for(AMQQueue queue : _queueRegistry.getQueues()) { AMQQueueMBean mbean = (AMQQueueMBean) queue.getManagedObject(); - + if(mbean == null) { continue; } - + List<Object> attributeValues = new ArrayList<Object>(attributesLength); - + for(int i=0; i < attributesLength; i++) { try @@ -174,13 +175,13 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr attributeValues.add(new String("-")); } } - + queueAttributesList.add(attributeValues); } - + return queueAttributesList; } - + /** * Creates new exchange and registers it with the registry. * @@ -277,7 +278,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr null); if (queue.isDurable() && !queue.isAutoDelete()) { - _messageStore.createQueue(queue); + _durableConfig.createQueue(queue); } _queueRegistry.registerQueue(queue); @@ -319,7 +320,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr queue.delete(); if (queue.isDurable()) { - _messageStore.removeQueue(queue); + _durableConfig.removeQueue(queue); } } catch (AMQException ex) @@ -330,7 +331,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } finally { - CurrentActor.remove(); + CurrentActor.remove(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 644a33db01..262bb2f226 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -20,24 +20,20 @@ */ package org.apache.qpid.server; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.framing.*; import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -47,23 +43,30 @@ import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.ClientDeliveryMethod; import org.apache.qpid.server.subscription.RecordDeliveryMethod; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.LocalTransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.txn.*; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.LogMessage; import org.apache.qpid.server.logging.messages.ChannelMessages; import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.logging.actors.AMQPChannelActor; import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.output.ProtocolOutputConverter; public class AMQChannel { public static final int DEFAULT_PREFETCH = 5000; - private static final Logger _log = Logger.getLogger(AMQChannel.class); + private static final Logger _logger = Logger.getLogger(AMQChannel.class); + + private static final boolean MSG_AUTH = + ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); + private final int _channelId; @@ -96,19 +99,12 @@ public class AMQChannel private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); - private final AtomicBoolean _suspended = new AtomicBoolean(false); + // Set of messages being acknoweledged in the current transaction + private SortedSet<QueueEntry> _acknowledgedMessages = new TreeSet<QueueEntry>(); - private TransactionalContext _txnContext; - - /** - * A context used by the message store enabling it to track context for a given channel even across thread - * boundaries - */ - private final StoreContext _storeContext; - - private final List<RequiredDeliveryException> _returnMessages = new LinkedList<RequiredDeliveryException>(); + private final AtomicBoolean _suspended = new AtomicBoolean(false); - private MessageHandleFactory _messageHandleFactory = new MessageHandleFactory(); + private ServerTransaction _transaction; // Why do we need this reference ? - ritchiem private final AMQProtocolSession _session; @@ -121,6 +117,12 @@ public class AMQChannel private LogActor _actor; private LogSubject _logSubject; + private volatile boolean _rollingBack; + + private static final Runnable NULL_TASK = new Runnable() { public void run() {} }; + private List<QueueEntry> _resendList = new ArrayList<QueueEntry>(); + private static final + AMQShortString IMMEDIATE_DELIVERY_REPLY_TEXT = new AMQShortString("Immediate delivery is not possible."); public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException @@ -130,22 +132,19 @@ public class AMQChannel _actor = new AMQPChannelActor(this, session.getLogActor().getRootMessageLogger()); _logSubject = new ChannelLogSubject(this); - - _actor.message(ChannelMessages.CHN_1001()); - - _storeContext = new StoreContext("Session: " + session.getClientIdentifier() + "; channel: " + channelId); + _actor.message(ChannelMessages.CHN_1001()); _messageStore = messageStore; // by default the session is non-transactional - _txnContext = new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); + _transaction = new AutoCommitTransaction(_messageStore); } /** Sets this channel to be part of a local transaction */ public void setLocalTransactional() { - _txnContext = new LocalTransactionalContext(this); + _transaction = new LocalTransaction(_messageStore); } public boolean isTransactional() @@ -153,7 +152,7 @@ public class AMQChannel // this does not look great but there should only be one "non-transactional" // transactional context, while there could be several transactional ones in // theory - return !(_txnContext instanceof NonTransactionalContext); + return !(_transaction instanceof AutoCommitTransaction); } public int getChannelId() @@ -164,8 +163,7 @@ public class AMQChannel public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException { - _currentMessage = new IncomingMessage(_messageStore.getNewMessageId(), info, _txnContext, _session); - _currentMessage.setMessageStore(_messageStore); + _currentMessage = new IncomingMessage(info); _currentMessage.setExchange(e); } @@ -178,18 +176,35 @@ public class AMQChannel } else { - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug("Content header received on channel " + _channelId); + _logger.debug("Content header received on channel " + _channelId); } _currentMessage.setContentHeaderBody(contentHeaderBody); _currentMessage.setExpiration(); + + MessageMetaData mmd = _currentMessage.headersReceived(); + final StoredMessage<MessageMetaData> handle = _messageStore.addMessage(mmd); + _currentMessage.setStoredMessage(handle); + routeCurrentMessage(); - _currentMessage.routingComplete(_messageStore, _messageHandleFactory); + + _transaction.addPostCommitAction(new ServerTransaction.Action() + { + + public void postCommit() + { + } + + public void onRollback() + { + handle.remove(); + } + }); deliverCurrentMessageIfComplete(); @@ -204,21 +219,36 @@ public class AMQChannel { try { - _currentMessage.deliverToQueues(); - } - catch (NoRouteException e) - { - _returnMessages.add(e); - } - catch(UnauthorizedAccessException ex) - { - _returnMessages.add(ex); + + final ArrayList<AMQQueue> destinationQueues = _currentMessage.getDestinationQueues(); + + if(!checkMessageUserId(_currentMessage.getContentHeader())) + { + _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.ACCESS_REFUSED, "Access Refused", _currentMessage)); + } + else + { + if(destinationQueues == null || _currentMessage.getDestinationQueues().isEmpty()) + { + if (_currentMessage.isMandatory() || _currentMessage.isImmediate()) + { + _transaction.addPostCommitAction(new WriteReturnAction(AMQConstant.NO_ROUTE, "No Route for message", _currentMessage)); + } + else + { + _logger.warn("MESSAGE DISCARDED: No routes for message - " + createAMQMessage(_currentMessage)); + } + + } + else + { + _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues)); + + } + } } finally { - // callback to allow the context to do any post message processing - // primary use is to allow message return processing in the non-tx case - _txnContext.messageProcessed(_session); _currentMessage = null; } } @@ -232,9 +262,9 @@ public class AMQChannel throw new AMQException("Received content body without previously receiving a JmsPublishBody"); } - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug(debugIdentity() + "Content body received on channel " + _channelId); + _logger.debug(debugIdentity() + "Content body received on channel " + _channelId); } try @@ -242,9 +272,10 @@ public class AMQChannel // returns true iff the message was delivered (i.e. if all data was // received - _currentMessage.addContentBodyFrame( - _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk( - contentBody)); + final ContentChunk contentChunk = + _session.getMethodRegistry().getProtocolVersionMethodConverter().convertToContentChunk(contentBody); + + _currentMessage.addContentBodyFrame(contentChunk); deliverCurrentMessageIfComplete(); } @@ -259,15 +290,7 @@ public class AMQChannel protected void routeCurrentMessage() throws AMQException { - try - { - _currentMessage.route(); - } - catch (NoRouteException e) - { - //_currentMessage.incrementReference(); - _returnMessages.add(e); - } + _currentMessage.route(); } public long getNextDeliveryTag() @@ -280,6 +303,12 @@ public class AMQChannel return ++_consumerTag; } + + public Subscription getSubscription(AMQShortString subscription) + { + return _tag2SubscriptionMap.get(subscription); + } + /** * Subscribe to a queue. We register all subscriptions in the channel so that if the channel is closed we can clean * up all subscriptions, even if the client does not explicitly unsubscribe from all queues. @@ -293,11 +322,10 @@ public class AMQChannel * @param exclusive Flag requesting exclusive access to the queue * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests * - * @throws ConsumerTagNotUniqueException if the tag is not unique * @throws AMQException if something goes wrong */ public AMQShortString subscribeToQueue(AMQShortString tag, AMQQueue queue, boolean acks, - FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException, ConsumerTagNotUniqueException + FieldTable filters, boolean noLocal, boolean exclusive) throws AMQException { if (tag == null) { @@ -306,7 +334,7 @@ public class AMQChannel if (_tag2SubscriptionMap.containsKey(tag)) { - throw new ConsumerTagNotUniqueException(); + throw new AMQException("Consumer already exists with same tag: " + tag); } Subscription subscription = @@ -344,12 +372,12 @@ public class AMQChannel Subscription sub = _tag2SubscriptionMap.remove(consumerTag); if (sub != null) { - try + try { sub.getSendLock(); sub.getQueue().unregisterSubscription(sub); } - finally + finally { sub.releaseSendLock(); } @@ -357,7 +385,7 @@ public class AMQChannel } else { - _log.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); + _logger.warn("Attempt to unsubscribe consumer with tag '"+consumerTag+"' which is not registered."); } return false; } @@ -369,18 +397,20 @@ public class AMQChannel */ public void close() throws AMQException { - _txnContext.rollback(); + setClosing(true); + unsubscribeAllConsumers(); + _transaction.rollback(); + try { requeue(); } catch (AMQException e) { - _log.error("Caught AMQException whilst attempting to reque:" + e); + _logger.error("Caught AMQException whilst attempting to reque:" + e); } - setClosing(true); } private void setClosing(boolean closing) @@ -392,23 +422,23 @@ public class AMQChannel private void unsubscribeAllConsumers() throws AMQException { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { if (!_tag2SubscriptionMap.isEmpty()) { - _log.info("Unsubscribing all consumers on channel " + toString()); + _logger.info("Unsubscribing all consumers on channel " + toString()); } else { - _log.info("No consumers to unsubscribe on channel " + toString()); + _logger.info("No consumers to unsubscribe on channel " + toString()); } } for (Map.Entry<AMQShortString, Subscription> me : _tag2SubscriptionMap.entrySet()) { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { - _log.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); + _logger.info("Unsubscribing consumer '" + me.getKey() + "' on channel " + toString()); } Subscription sub = me.getValue(); @@ -422,7 +452,7 @@ public class AMQChannel { sub.releaseSendLock(); } - + } _tag2SubscriptionMap.clear(); @@ -438,17 +468,17 @@ public class AMQChannel */ public void addUnacknowledgedMessage(QueueEntry entry, long deliveryTag, Subscription subscription) { - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { if (entry.getQueue() == null) { - _log.debug("Adding unacked message with a null queue:" + entry.debugIdentity()); + _logger.debug("Adding unacked message with a null queue:" + entry); } else { - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + _logger.debug(debugIdentity() + " Adding unacked message(" + entry.getMessage().toString() + " DT:" + deliveryTag + ") with a queue(" + entry.getQueue() + ") for " + subscription); } } @@ -476,27 +506,13 @@ public class AMQChannel // we must create a new map since all the messages will get a new delivery tag when they are redelivered Collection<QueueEntry> messagesToBeDelivered = _unacknowledgedMessageMap.cancelAllMessages(); - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext = null; - if (!messagesToBeDelivered.isEmpty()) { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { - _log.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); + _logger.info("Requeuing " + messagesToBeDelivered.size() + " unacked messages. for " + toString()); } - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - else - { - deliveryContext = _txnContext; - } } for (QueueEntry unacked : messagesToBeDelivered) @@ -504,18 +520,15 @@ public class AMQChannel if (!unacked.isQueueDeleted()) { // Mark message redelivered - unacked.getMessage().setRedelivered(true); + unacked.setRedelivered(); // Ensure message is released for redelivery unacked.release(); - // Deliver Message - deliveryContext.requeue(unacked); - } else { - unacked.discard(_storeContext); + unacked.discard(); } } @@ -535,48 +548,27 @@ public class AMQChannel if (unacked != null) { // Mark message redelivered - unacked.getMessage().setRedelivered(true); + unacked.setRedelivered(); // Ensure message is released for redelivery if (!unacked.isQueueDeleted()) { - unacked.release(); - } - - - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - - } - else - { - deliveryContext = _txnContext; - } + // Ensure message is released for redelivery + unacked.release(); - if (!unacked.isQueueDeleted()) - { - // Redeliver the messages to the front of the queue - deliveryContext.requeue(unacked); - // Deliver increments the message count but we have already deliverted this once so don't increment it again - // this was because deliver did an increment changed this. } else { - _log.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked.getMessage().debugIdentity() + _logger.warn(System.identityHashCode(this) + " Requested requeue of message(" + unacked + "):" + deliveryTag + " but no queue defined and no DeadLetter queue so DROPPING message."); - unacked.discard(_storeContext); + unacked.discard(); } } else { - _log.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _logger.warn("Requested requeue of message:" + deliveryTag + " but no such delivery tag exists." + _unacknowledgedMessageMap.size()); } @@ -597,28 +589,31 @@ public class AMQChannel final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>(); final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>(); - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { - _log.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); + _logger.debug("unacked map Size:" + _unacknowledgedMessageMap.size()); } // Process the Unacked-Map. // Marking messages who still have a consumer for to be resent // and those that don't to be requeued. - _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, requeue, _storeContext)); + _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, + msgToRequeue, + msgToResend, + requeue, + _messageStore)); // Process Messages to Resend - if (_log.isDebugEnabled()) + if (_logger.isDebugEnabled()) { if (!msgToResend.isEmpty()) { - _log.debug("Preparing (" + msgToResend.size() + ") message to resend."); + _logger.debug("Preparing (" + msgToResend.size() + ") message to resend."); } else { - _log.debug("No message to resend."); + _logger.debug("No message to resend."); } } @@ -629,7 +624,7 @@ public class AMQChannel - AMQMessage msg = message.getMessage(); + ServerMessage msg = message.getMessage(); AMQQueue queue = message.getQueue(); // Our Java Client will always suspend the channel when resending! @@ -638,7 +633,7 @@ public class AMQChannel // i.e. The channel hasn't been server side suspended. // if (isSuspended()) // { - // _log.info("Channel is suspended so requeuing"); + // _logger.info("Channel is suspended so requeuing"); // //move this message to requeue // msgToRequeue.add(message); // } @@ -648,14 +643,14 @@ public class AMQChannel // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. - msg.setRedelivered(true); + message.setRedelivered(); Subscription sub = message.getDeliveredSubscription(); if (sub != null) { - - if(!queue.resend(message, sub)) + + if(!queue.resend(message,sub)) { msgToRequeue.put(deliveryTag, message); } @@ -663,9 +658,9 @@ public class AMQChannel else { - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { - _log.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + _logger.info("DeliveredSubscription not recorded so just requeueing(" + message.toString() + ")to prevent loss"); } // move this message to requeue @@ -674,91 +669,28 @@ public class AMQChannel } // for all messages // } else !isSuspend - if (_log.isInfoEnabled()) + if (_logger.isInfoEnabled()) { if (!msgToRequeue.isEmpty()) { - _log.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); + _logger.info("Preparing (" + msgToRequeue.size() + ") message to requeue to."); } } - // Deliver these messages out of the transaction as their delivery was never - // part of the transaction only the receive. - TransactionalContext deliveryContext; - if (!(_txnContext instanceof NonTransactionalContext)) - { - - deliveryContext = - new NonTransactionalContext(_messageStore, _storeContext, this, _returnMessages); - } - else - { - deliveryContext = _txnContext; - } - // Process Messages to Requeue at the front of the queue for (Map.Entry<Long, QueueEntry> entry : msgToRequeue.entrySet()) { QueueEntry message = entry.getValue(); long deliveryTag = entry.getKey(); - - message.release(); - message.setRedelivered(true); + _unacknowledgedMessageMap.remove(deliveryTag); - deliveryContext.requeue(message); + message.setRedelivered(); + message.release(); - _unacknowledgedMessageMap.remove(deliveryTag); } } - /** - * Callback indicating that a queue has been deleted. We must update the structure of unacknowledged messages to - * remove the queue reference and also decrement any message reference counts, without actually removing the item - * since we may get an ack for a delivery tag that was generated from the deleted queue. - * - * @param queue the queue that has been deleted - * - */ - /* public void queueDeleted(final AMQQueue queue) - { - try - { - _unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(UnacknowledgedMessage message) - { - if (message.getQueue() == queue) - { - try - { - message.discard(_storeContext); - message.setQueueDeleted(true); - - } - catch (AMQException e) - { - _log.error( - "Error decrementing ref count on message " + message.getMessage().getMessageId() + ": " + e, e); - throw new RuntimeException(e); - } - } - - return false; - } - - public void visitComplete() - { - } - }); - } - catch (AMQException e) - { - _log.error("Unexpected Error while handling deletion of queue", e); - throw new RuntimeException(e); - } - } -*/ /** * Acknowledge one or more messages. * @@ -770,7 +702,17 @@ public class AMQChannel */ public void acknowledgeMessage(long deliveryTag, boolean multiple) throws AMQException { - _unacknowledgedMessageMap.acknowledgeMessage(deliveryTag, multiple, _txnContext); + Collection<QueueEntry> ackedMessages = getAckedMessages(deliveryTag, multiple); + _transaction.dequeue(ackedMessages, new MessageAcknowledgeAction(ackedMessages)); + } + + private Collection<QueueEntry> getAckedMessages(long deliveryTag, boolean multiple) + { + + Map<Long, QueueEntry> ackedMessageMap = new LinkedHashMap<Long,QueueEntry>(); + _unacknowledgedMessageMap.collect(deliveryTag, multiple, ackedMessageMap); + _unacknowledgedMessageMap.remove(ackedMessageMap); + return ackedMessageMap.values(); } /** @@ -854,7 +796,7 @@ public class AMQChannel public boolean isSuspended() { - return _suspended.get(); + return _suspended.get() || _closing || _session.isClosing(); } public void commit() throws AMQException @@ -864,57 +806,87 @@ public class AMQChannel throw new AMQException("Fatal error: commit called on non-transactional channel"); } - _txnContext.commit(); + _transaction.commit(); + } public void rollback() throws AMQException { - _txnContext.rollback(); + rollback(NULL_TASK); } - public String toString() + public void rollback(Runnable postRollbackTask) throws AMQException { - return "["+_session.toString()+":"+_channelId+"]"; - } + if (!isTransactional()) + { + throw new AMQException("Fatal error: commit called on non-transactional channel"); + } - public void setDefaultQueue(AMQQueue queue) - { - _defaultQueue = queue; - } + // stop all subscriptions + _rollingBack = true; + boolean requiresSuspend = _suspended.compareAndSet(false,true); - public AMQQueue getDefaultQueue() - { - return _defaultQueue; - } + // ensure all subscriptions have seen the change to the channel state + for(Subscription sub : _tag2SubscriptionMap.values()) + { + sub.getSendLock(); + sub.releaseSendLock(); + } - public StoreContext getStoreContext() - { - return _storeContext; - } + try + { + _transaction.rollback(); + } + finally + { + _rollingBack = false; + } - public void processReturns() throws AMQException - { - if (!_returnMessages.isEmpty()) + postRollbackTask.run(); + + for(QueueEntry entry : _resendList) { - for (RequiredDeliveryException bouncedMessage : _returnMessages) + Subscription sub = entry.getDeliveredSubscription(); + if(sub == null || sub.isClosed()) { - AMQMessage message = bouncedMessage.getAMQMessage(); - _session.getProtocolOutputConverter().writeReturn(message, _channelId, bouncedMessage.getReplyCode().getCode(), - new AMQShortString(bouncedMessage.getMessage())); + entry.release(); + } + else + { + sub.getQueue().resend(entry, sub); + } + } + _resendList.clear(); - message.decrementReference(_storeContext); + if(requiresSuspend) + { + _suspended.set(false); + for(Subscription sub : _tag2SubscriptionMap.values()) + { + sub.getQueue().deliverAsync(sub); } - _returnMessages.clear(); } + + } + public String toString() + { + return "["+_session.toString()+":"+_channelId+"]"; + } - public TransactionalContext getTransactionalContext() + public void setDefaultQueue(AMQQueue queue) { - return _txnContext; + _defaultQueue = queue; } + public AMQQueue getDefaultQueue() + { + return _defaultQueue; + } + + public boolean isClosing() { return _closing; @@ -936,11 +908,6 @@ public class AMQChannel _creditManager.setCreditLimits(prefetchSize, prefetchCount); } - public List<RequiredDeliveryException> getReturnMessages() - { - return _returnMessages; - } - public MessageStore getMessageStore() { return _messageStore; @@ -952,8 +919,10 @@ public class AMQChannel public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) throws AMQException { - getProtocolSession().getProtocolOutputConverter().writeDeliver(entry.getMessage(), getChannelId(), deliveryTag, sub.getConsumerTag()); + getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(), + deliveryTag, sub.getConsumerTag()); } + }; public ClientDeliveryMethod getClientDeliveryMethod() @@ -975,6 +944,213 @@ public class AMQChannel return _recordDeliveryMethod; } + + private AMQMessage createAMQMessage(IncomingMessage incomingMessage) + throws AMQException + { + + AMQMessage message = new AMQMessage(incomingMessage.getStoredMessage()); + + message.setExpiration(incomingMessage.getExpiration()); + message.setClientIdentifier(_session); + return message; + } + + private boolean checkMessageUserId(ContentHeaderBody header) + { + AMQShortString userID = + header.properties instanceof BasicContentHeaderProperties + ? ((BasicContentHeaderProperties) header.properties).getUserId() + : null; + + return (!MSG_AUTH || _session.getPrincipal().getName().equals(userID == null? "" : userID.toString())); + + } + + private class MessageDeliveryAction implements ServerTransaction.Action + { + private IncomingMessage _incommingMessage; + private ArrayList<AMQQueue> _destinationQueues; + + public MessageDeliveryAction(IncomingMessage currentMessage, + ArrayList<AMQQueue> destinationQueues) + { + _incommingMessage = currentMessage; + _destinationQueues = destinationQueues; + } + + public void postCommit() + { + try + { + final boolean immediate = _incommingMessage.isImmediate(); + + final AMQMessage amqMessage = createAMQMessage(_incommingMessage); + MessageReference ref = amqMessage.newReference(); + + for(AMQQueue queue : _destinationQueues) + { + + QueueEntry entry = queue.enqueue(amqMessage); + queue.checkCapacity(AMQChannel.this); + + + if(immediate && !entry.getDeliveredToConsumer() && entry.acquire()) + { + + + ServerTransaction txn = new LocalTransaction(_messageStore); + Collection<QueueEntry> entries = new ArrayList<QueueEntry>(1); + entries.add(entry); + final AMQMessage message = (AMQMessage) entry.getMessage(); + txn.dequeue(queue, entry.getMessage(), + new MessageAcknowledgeAction(entries) + { + @Override + public void postCommit() + { + try + { + final + ProtocolOutputConverter outputConverter = + _session.getProtocolOutputConverter(); + + outputConverter.writeReturn(message.getMessagePublishInfo(), + message.getContentHeaderBody(), + message, + _channelId, + AMQConstant.NO_CONSUMERS.getCode(), + IMMEDIATE_DELIVERY_REPLY_TEXT); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + super.postCommit(); + } + } + ); + txn.commit(); + + + + + } + + } + ref.release(); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + + + + + + } + + public void onRollback() + { + // Maybe keep track of entries that were created and then delete them here in case of failure + // to in memory enqueue + } + } + + private class MessageAcknowledgeAction implements ServerTransaction.Action + { + private final Collection<QueueEntry> _ackedMessages; + + + public MessageAcknowledgeAction(Collection<QueueEntry> ackedMessages) + { + _ackedMessages = ackedMessages; + } + + public void postCommit() + { + try + { + for(QueueEntry entry : _ackedMessages) + { + entry.discard(); + } + } + finally + { + _acknowledgedMessages.clear(); + } + + } + + public void onRollback() + { + // explicit rollbacks resend the message after the rollback-ok is sent + if(_rollingBack) + { + _resendList.addAll(_ackedMessages); + } + else + { + try + { + for(QueueEntry entry : _ackedMessages) + { + entry.release(); + } + } + finally + { + _acknowledgedMessages.clear(); + } + } + + } + } + + private class WriteReturnAction implements ServerTransaction.Action + { + private final AMQConstant _errorCode; + private final IncomingMessage _message; + private final String _description; + + public WriteReturnAction(AMQConstant errorCode, + String description, + IncomingMessage message) + { + _errorCode = errorCode; + _message = message; + _description = description; + } + + public void postCommit() + { + try + { + _session.getProtocolOutputConverter().writeReturn(_message.getMessagePublishInfo(), + _message.getContentHeader(), + _message, + _channelId, + _errorCode.getCode(), + new AMQShortString(_description)); + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + + } + + public void onRollback() + { + //To change body of implemented methods use File | Settings | File Templates. + } + } + + public LogActor getLogActor() { return _actor; @@ -993,7 +1169,7 @@ public class AMQChannel } } - public void unblock(AMQQueue queue) + public void unblock(AMQQueue queue) { if(_blockingQueues.remove(queue)) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java index 29494c4118..9da02e0600 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java @@ -21,11 +21,11 @@ package org.apache.qpid.server; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; @@ -35,30 +35,29 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor { private static final Logger _log = Logger.getLogger(ExtractResendAndRequeue.class); - private Map<Long, QueueEntry> _msgToRequeue; - private Map<Long, QueueEntry> _msgToResend; - private boolean _requeueIfUnabletoResend; - private StoreContext _storeContext; - private UnacknowledgedMessageMap _unacknowledgedMessageMap; + private final Map<Long, QueueEntry> _msgToRequeue; + private final Map<Long, QueueEntry> _msgToResend; + private final boolean _requeueIfUnabletoResend; + private final UnacknowledgedMessageMap _unacknowledgedMessageMap; + private final TransactionLog _transactionLog; - public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, + public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, Map<Long, QueueEntry> msgToRequeue, Map<Long, QueueEntry> msgToResend, boolean requeueIfUnabletoResend, - StoreContext storeContext) + TransactionLog txnLog) { _unacknowledgedMessageMap = unacknowledgedMessageMap; _msgToRequeue = msgToRequeue; _msgToResend = msgToResend; _requeueIfUnabletoResend = requeueIfUnabletoResend; - _storeContext = storeContext; + _transactionLog = txnLog; } public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException { - AMQMessage msg = message.getMessage(); - msg.setRedelivered(true); + message.setRedelivered(); final Subscription subscription = message.getDeliveredSubscription(); if (subscription != null) { @@ -85,13 +84,14 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor } else { - message.discard(_storeContext); + + dequeueEntry(message); _log.info("No DeadLetter Queue and requeue not requested so dropping message:" + message); } } else { - message.discard(_storeContext); + dequeueEntry(message); _log.warn("Message.queue is null and no DeadLetter Queue so dropping message:" + message); } } @@ -100,6 +100,31 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor return false; } + + private void dequeueEntry(final QueueEntry node) + { + ServerTransaction txn = new AutoCommitTransaction(_transactionLog); + dequeueEntry(node, txn); + } + + private void dequeueEntry(final QueueEntry node, ServerTransaction txn) + { + txn.dequeue(node.getQueue(), node.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + node.discard(); + } + + public void onRollback() + { + + } + }); + } + public void visitComplete() { _unacknowledgedMessageMap.clear(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index c45e794145..0a2bd6e8b0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -26,6 +26,11 @@ import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Properties; +import java.util.Set; +import java.util.HashSet; +import java.util.List; +import java.util.Collection; +import java.util.Arrays; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -37,7 +42,8 @@ import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator; -import org.apache.qpid.AMQException; +import org.apache.qpid.transport.network.ConnectionBinding; +import org.apache.qpid.transport.*; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -49,12 +55,16 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AMQProtocolEngineFactory; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.transport.ServerConnection; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.ssl.SSLContextFactory; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.network.mina.MINANetworkDriver; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; /** * Main entry point for AMQPD. @@ -73,6 +83,7 @@ public class Main private static final int IPV4_ADDRESS_LENGTH = 4; private static final char IPV4_LITERAL_SEPARATOR = '.'; + private static final Collection<VERSION> ALL_VERSIONS = Arrays.asList(VERSION.values()); protected static class InitException extends Exception { @@ -123,6 +134,24 @@ public class Main OptionBuilder.withArgName("port").hasArg() .withDescription("listen on the specified port. Overrides any value in the config file") .withLongOpt("port").create("p"); + + Option exclude0_10 = + OptionBuilder.withArgName("exclude-0-10").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-10 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-10").create(); + + Option exclude0_9 = + OptionBuilder.withArgName("exclude-0-9").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-9 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-9").create(); + + + Option exclude0_8 = + OptionBuilder.withArgName("exclude-0-8").hasArg() + .withDescription("when listening on the specified port do not accept AMQP0-8 connections. The specified port must be one specified on the command line") + .withLongOpt("exclude-0-8").create(); + + Option mport = OptionBuilder.withArgName("mport").hasArg() .withDescription("listen on the specified management port. Overrides any value in the config file") @@ -149,6 +178,9 @@ public class Main options.addOption(logconfig); options.addOption(logwatchconfig); options.addOption(port); + options.addOption(exclude0_10); + options.addOption(exclude0_9); + options.addOption(exclude0_8); options.addOption(mport); options.addOption(bind); } @@ -239,7 +271,7 @@ public class Main String logConfig = commandLine.getOptionValue("l"); String logWatchConfig = commandLine.getOptionValue("w", "0"); - + int logWatchTime = 0; try { @@ -250,7 +282,7 @@ public class Main System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + "a non-negative integer. Using default of zero (no watching configured"); } - + File logConfigFile; if (logConfig != null) { @@ -276,9 +308,12 @@ public class Main BrokerMessages.reload(); // AR.initialise() sets its own actor so we now need to set the actor - // for the remainder of the startup + // for the remainder of the startup CurrentActor.set(new BrokerActor(config.getRootMessageLogger())); - try{ + CurrentActor.setDefault(new BrokerActor(config.getRootMessageLogger())); + + try + { configureLoggingManagementMBean(logConfigFile, logWatchTime); ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); @@ -294,20 +329,35 @@ public class Main _brokerLogger.info("Starting Qpid Broker " + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); - int port = serverConfig.getPort(); - String portStr = commandLine.getOptionValue("p"); - if (portStr != null) + + String[] portStr = commandLine.getOptionValues("p"); + + Set<Integer> ports = new HashSet<Integer>(); + Set<Integer> exclude_0_10 = new HashSet<Integer>(); + Set<Integer> exclude_0_9 = new HashSet<Integer>(); + Set<Integer> exclude_0_8 = new HashSet<Integer>(); + + if(portStr == null || portStr.length == 0) { - try - { - port = Integer.parseInt(portStr); - } - catch (NumberFormatException e) - { - throw new InitException("Invalid port: " + portStr, e); - } + + parsePortList(ports, serverConfig.getPorts()); + parsePortList(exclude_0_10, serverConfig.getPortExclude010()); + parsePortList(exclude_0_9, serverConfig.getPortExclude09()); + parsePortList(exclude_0_8, serverConfig.getPortExclude08()); + } + else + { + parsePortArray(ports, portStr); + parsePortArray(exclude_0_10, commandLine.getOptionValues("exclude-0-10")); + parsePortArray(exclude_0_9, commandLine.getOptionValues("exclude-0-9")); + parsePortArray(exclude_0_8, commandLine.getOptionValues("exclude-0-8")); + + } + + + String bindAddr = commandLine.getOptionValue("b"); if (bindAddr == null) @@ -315,42 +365,75 @@ public class Main bindAddr = serverConfig.getBind(); } InetAddress bindAddress = null; + + + if (bindAddr.equals("wildcard")) { - bindAddress = new InetSocketAddress(port).getAddress(); + bindAddress = new InetSocketAddress(0).getAddress(); } else { bindAddress = InetAddress.getByAddress(parseIP(bindAddr)); } + String hostName = bindAddress.getCanonicalHostName(); + + String keystorePath = serverConfig.getKeystorePath(); String keystorePassword = serverConfig.getKeystorePassword(); String certType = serverConfig.getCertType(); SSLContextFactory sslFactory = null; - boolean isSsl = false; - + if (!serverConfig.getSSLOnly()) { - NetworkDriver driver = new MINANetworkDriver(); - driver.bind(port, new InetAddress[]{bindAddress}, new AMQProtocolEngineFactory(), - serverConfig.getNetworkConfiguration(), null); - ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), - new QpidAcceptor(driver,"TCP")); - CurrentActor.get().message(BrokerMessages.BRK_1002("TCP", port)); + + for(int port : ports) + { + + NetworkDriver driver = new MINANetworkDriver(); + + Set<VERSION> supported = new HashSet<VERSION>(ALL_VERSIONS); + + if(exclude_0_10.contains(port)) + { + supported.remove(VERSION.v0_10); + } + if(exclude_0_9.contains(port)) + { + supported.remove(VERSION.v0_9); + } + if(exclude_0_8.contains(port)) + { + supported.remove(VERSION.v0_8); + } + + MultiVersionProtocolEngineFactory protocolEngineFactory = + new MultiVersionProtocolEngineFactory(hostName, supported); + + + + driver.bind(port, new InetAddress[]{bindAddress}, protocolEngineFactory, + serverConfig.getNetworkConfiguration(), null); + ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), + new QpidAcceptor(driver,"TCP")); + CurrentActor.get().message(BrokerMessages.BRK_1002("TCP", port)); + + } + } - + if (serverConfig.getEnableSSL()) { sslFactory = new SSLContextFactory(keystorePath, keystorePassword, certType); NetworkDriver driver = new MINANetworkDriver(); - driver.bind(serverConfig.getSSLPort(), new InetAddress[]{bindAddress}, + driver.bind(serverConfig.getSSLPort(), new InetAddress[]{bindAddress}, new AMQProtocolEngineFactory(), serverConfig.getNetworkConfiguration(), sslFactory); - ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, port), + ApplicationRegistry.getInstance().addAcceptor(new InetSocketAddress(bindAddress, serverConfig.getSSLPort()), new QpidAcceptor(driver,"TCP")); CurrentActor.get().message(BrokerMessages.BRK_1002("TCP/SSL", serverConfig.getSSLPort())); } - + //fixme qpid.AMQP should be using qpidproperties to get value _brokerLogger.info("Qpid Broker Ready :" + QpidProperties.getReleaseVersion() + " build: " + QpidProperties.getBuildVersion()); @@ -363,6 +446,47 @@ public class Main // Startup is complete so remove the AR initialised Startup actor CurrentActor.remove(); } + + + + } + + private void parsePortArray(Set<Integer> ports, String[] portStr) + throws InitException + { + if(portStr != null) + { + for(int i = 0; i < portStr.length; i++) + { + try + { + ports.add(Integer.parseInt(portStr[i])); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + portStr[i], e); + } + } + } + } + + private void parsePortList(Set<Integer> output, List input) + throws InitException + { + if(input != null) + { + for(Object port : input) + { + try + { + output.add(Integer.parseInt(String.valueOf(port))); + } + catch (NumberFormatException e) + { + throw new InitException("Invalid port: " + port, e); + } + } + } } /** @@ -394,11 +518,11 @@ public class Main { System.setProperty("log4j.defaultInitOverride", "true"); } - + //now that the override status is know, we can instantiate the Loggers _logger = Logger.getLogger(Main.class); _brokerLogger = Logger.getLogger("Qpid.Broker"); - + new Main(args); } @@ -434,7 +558,7 @@ public class Main { if (logConfigFile.exists() && logConfigFile.canRead()) { - CurrentActor.get().message(BrokerMessages.BRK_1007(logConfigFile.getAbsolutePath())); + CurrentActor.get().message(BrokerMessages.BRK_1007(logConfigFile.getAbsolutePath())); System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); if (logWatchTime > 0) { @@ -466,7 +590,7 @@ public class Main { System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); System.err.println("Using the fallback internal log4j.properties configuration"); - + InputStream propsFile = this.getClass().getResourceAsStream("/log4j.properties"); if(propsFile == null) { @@ -484,14 +608,7 @@ public class Main private void configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception { LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime); - - try - { - blm.register(); - } - catch (AMQException e) - { - throw new InitException("Unable to initialise the Logging Management MBean: ", e); - } + + blm.register(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java deleted file mode 100644 index 3f1947d65a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/RequiredDeliveryException.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.queue.AMQMessage; - -/** - * Signals that a required delivery could not be made. This could be bacuse of the immediate flag being set and the - * queue having no consumers, or the mandatory flag being set and the exchange having no valid bindings. - * - * <p/>The failed message is associated with this error condition, by taking a reference to it. This enables the - * correct compensating action to be taken against the message, for example, bouncing it back to the sender. - * - * <p/><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities <th> Collaborations - * <tr><td> Represent failure to deliver a message that must be delivered. - * <tr><td> Associate the failed message with the error condition. <td> {@link AMQMessage} - * </table> - */ -public abstract class RequiredDeliveryException extends AMQException -{ - private AMQMessage _amqMessage; - - public RequiredDeliveryException(String message, AMQMessage payload) - { - super(message); - - setMessage(payload); - } - - - public RequiredDeliveryException(String message) - { - super(message); - } - - public void setMessage(final AMQMessage payload) - { - - // Increment the reference as this message is in the routing phase - // and so will have the ref decremented as routing fails. - // we need to keep this message around so we can return it in the - // handler. So increment here. - _amqMessage = payload.takeReference(); - - } - - public AMQMessage getAMQMessage() - { - return _amqMessage; - } - - public AMQConstant getErrorCode() - { - return getReplyCode(); - } - - public abstract AMQConstant getReplyCode(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java deleted file mode 100644 index db3a05eb52..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/TxAck.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.ArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TxnOp; -import org.apache.qpid.server.queue.QueueEntry; - -/** - * A TxnOp implementation for handling accumulated acks - */ -public class TxAck implements TxnOp -{ - private final UnacknowledgedMessageMap _map; - private final Map<Long, QueueEntry> _unacked = new HashMap<Long,QueueEntry>(); - private List<Long> _individual; - private long _deliveryTag; - private boolean _multiple; - - public TxAck(UnacknowledgedMessageMap map) - { - _map = map; - } - - public void update(long deliveryTag, boolean multiple) - { - _unacked.clear(); - if (!multiple) - { - if(_individual == null) - { - _individual = new ArrayList<Long>(); - } - //have acked a single message that is not part of - //the previously acked region so record - //individually - _individual.add(deliveryTag);//_multiple && !multiple - } - else if (deliveryTag > _deliveryTag) - { - //have simply moved the last acked message on a - //bit - _deliveryTag = deliveryTag; - _multiple = true; - } - } - - public void consolidate() - { - if(_unacked.isEmpty()) - { - //lookup all the unacked messages that have been acked in this transaction - if (_multiple) - { - //get all the unacked messages for the accumulated - //multiple acks - _map.collect(_deliveryTag, true, _unacked); - } - if(_individual != null) - { - //get any unacked messages for individual acks outside the - //range covered by multiple acks - for (long tag : _individual) - { - if(_deliveryTag < tag) - { - _map.collect(tag, false, _unacked); - } - } - } - } - } - - public boolean checkPersistent() throws AMQException - { - consolidate(); - //if any of the messages in unacked are persistent the txn - //buffer must be marked as persistent: - for (QueueEntry msg : _unacked.values()) - { - if (msg.getMessage().isPersistent()) - { - return true; - } - } - return false; - } - - public void prepare(StoreContext storeContext) throws AMQException - { - //make persistent changes, i.e. dequeue and decrementReference - for (QueueEntry msg : _unacked.values()) - { - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(storeContext); - - } - } - - public void undoPrepare() - { - //decrementReference is annoyingly untransactional (due to - //in memory counter) so if we failed in prepare for full - //txn, this op will have to compensate by fixing the count - //in memory (persistent changes will be rolled back by store) - for (QueueEntry msg : _unacked.values()) - { - msg.getMessage().takeReference(); - } - } - - public void commit(StoreContext storeContext) - { - //remove the unacked messages from the channels map - _map.remove(_unacked); - } - - public void rollback(StoreContext storeContext) - { - } -} - - diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java index c80a96f967..3bad73d86d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java @@ -21,14 +21,12 @@ package org.apache.qpid.server.ack; import java.util.Collection; -import java.util.List; import java.util.Set; import java.util.Map; import org.apache.qpid.AMQException; -import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; + public interface UnacknowledgedMessageMap { @@ -50,18 +48,12 @@ public interface UnacknowledgedMessageMap void collect(long deliveryTag, boolean multiple, Map<Long, QueueEntry> msgs); - boolean contains(long deliveryTag) throws AMQException; - void remove(Map<Long,QueueEntry> msgs); QueueEntry remove(long deliveryTag); - public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException; - Collection<QueueEntry> cancelAllMessages(); - void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) throws AMQException; - int size(); void clear(); @@ -75,7 +67,6 @@ public interface UnacknowledgedMessageMap */ Set<Long> getDeliveryTags(); - public long getUnacknowledgeBytes(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java index c567387662..d920d97c1a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java @@ -20,20 +20,13 @@ */ package org.apache.qpid.server.ack; -import org.apache.qpid.server.store.StoreContext; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.txn.TransactionalContext; public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap { @@ -61,19 +54,15 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } else { - msgs.put(deliveryTag, get(deliveryTag)); + final QueueEntry entry = get(deliveryTag); + if(entry != null) + { + msgs.put(deliveryTag, entry); + } } } - public boolean contains(long deliveryTag) throws AMQException - { - synchronized (_lock) - { - return _map.containsKey(deliveryTag); - } - } - public void remove(Map<Long,QueueEntry> msgs) { synchronized (_lock) @@ -135,15 +124,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void acknowledgeMessage(long deliveryTag, boolean multiple, TransactionalContext txnContext) - throws AMQException - { - synchronized (_lock) - { - txnContext.acknowledgeMessage(deliveryTag, _lastDeliveryTag, multiple, this); - } - } - public int size() { synchronized (_lock) @@ -161,39 +141,6 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public void drainTo(long deliveryTag, StoreContext storeContext) throws AMQException - - { - synchronized (_lock) - { - Iterator<Map.Entry<Long, QueueEntry>> it = _map.entrySet().iterator(); - while (it.hasNext()) - { - Map.Entry<Long, QueueEntry> unacked = it.next(); - - if (unacked.getKey() > deliveryTag) - { - //This should not occur now. - throw new AMQException("UnacknowledgedMessageMap is out of order:" + unacked.getKey() + - " When deliveryTag is:" + deliveryTag + "ES:" + _map.entrySet().toString()); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - unacked.getValue().discard(storeContext); - - it.remove(); - - _unackedSize -= unacked.getValue().getMessage().getSize(); - - - if (unacked.getKey() == deliveryTag) - { - break; - } - } - } - } - public QueueEntry get(long key) { synchronized (_lock) @@ -225,8 +172,4 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } - public long getUnacknowledgeBytes() - { - return _unackedSize; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 641b44bb18..7bf28c7560 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -14,8 +14,8 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. - * + * under the License. + * */ package org.apache.qpid.server.configuration; @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Locale; +import java.util.Collections; import java.util.Map.Entry; import org.apache.commons.configuration.CompositeConfiguration; @@ -124,7 +125,7 @@ public class ServerConfiguration implements SignalHandler } catch (IllegalArgumentException e) { - // We're on something that doesn't handle SIGHUP, how sad, Windows. + // We're on something that doesn't handle SIGHUP, how sad, Windows. } } @@ -221,7 +222,7 @@ public class ServerConfiguration implements SignalHandler String localeString = getConfig().getString(ADVANCED_LOCALE); // Expecting locale of format langauge_country_variant - // If the configuration does not have a defined locale use the JVM default + // If the configuration does not have a defined locale use the JVM default if (localeString == null) { return Locale.getDefault(); @@ -524,11 +525,27 @@ public class ServerConfiguration implements SignalHandler return getConfig().getInt("connector.processors", 4); } - public int getPort() + public List getPorts() + { + return getConfig().getList("connector.port", Collections.singletonList(DEFAULT_PORT)); + } + + public List getPortExclude010() + { + return getConfig().getList("connector.non010port", Collections.EMPTY_LIST); + } + + public List getPortExclude09() + { + return getConfig().getList("connector.non09port", Collections.EMPTY_LIST); + } + + public List getPortExclude08() { - return getConfig().getInt("connector.port", DEFAULT_PORT); + return getConfig().getList("connector.non08port", Collections.EMPTY_LIST); } + public String getBind() { return getConfig().getString("connector.bind", "wildcard"); @@ -625,48 +642,48 @@ public class ServerConfiguration implements SignalHandler { return new NetworkDriverConfiguration() { - + public Integer getTrafficClass() { return null; } - + public Boolean getTcpNoDelay() { // Can't call parent getTcpNoDelay since it just calls this one return getConfig().getBoolean("connector.tcpNoDelay", true); } - + public Integer getSoTimeout() { return null; } - + public Integer getSoLinger() { return null; } - + public Integer getSendBufferSize() { return getBufferWriteLimit(); } - + public Boolean getReuseAddress() { return null; } - + public Integer getReceiveBufferSize() { return getBufferReadLimit(); } - + public Boolean getOOBInline() { return null; } - + public Boolean getKeepAlive() { return null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index bb70ce556b..7983c62443 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,6 +23,7 @@ package org.apache.qpid.server.exchange; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; +import javax.management.JMException; import javax.management.openmbean.OpenType; import javax.management.openmbean.CompositeType; import javax.management.openmbean.TabularType; @@ -39,18 +40,23 @@ import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.ExchangeMessages; import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; import org.apache.qpid.server.logging.LogSubject; +import org.apache.log4j.Logger; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public abstract class AbstractExchange implements Exchange, Managable { private AMQShortString _name; - + private Exchange _alternateExchange; protected boolean _durable; protected String _exchangeType; @@ -67,6 +73,7 @@ public abstract class AbstractExchange implements Exchange, Managable //The logSubject for ths exchange private LogSubject _logSubject; + private Map<ExchangeReferrer,Object> _referrers = new ConcurrentHashMap<ExchangeReferrer,Object>(); /** * Abstract MBean class. This has some of the methods implemented from @@ -80,14 +87,14 @@ public abstract class AbstractExchange implements Exchange, Managable protected CompositeType _bindingDataType; protected TabularType _bindinglistDataType; protected TabularDataSupport _bindingList; - + public ExchangeMBean() throws NotCompliantMBeanException { super(ManagedExchange.class, ManagedExchange.TYPE, ManagedExchange.VERSION); } protected void init() throws OpenDataException - { + { _bindingItemTypes = new OpenType[2]; _bindingItemTypes[0] = SimpleType.STRING; _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); @@ -156,23 +163,33 @@ public abstract class AbstractExchange implements Exchange, Managable * called during initialisation (template method pattern). * @return the MBean */ - protected abstract ExchangeMBean createMBean() throws AMQException; + protected abstract ExchangeMBean createMBean() throws JMException; - public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException + public void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) + throws AMQException { _virtualHost = host; _name = name; _durable = durable; _autoDelete = autoDelete; _ticket = ticket; - _exchangeMbean = createMBean(); - _exchangeMbean.register(); + try + { + _exchangeMbean = createMBean(); + _exchangeMbean.register(); + } + catch (JMException e) + { + getLogger().error(e); + } _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation CurrentActor.get().message(ExchangeMessages.EXH_1001(String.valueOf(getType()), String.valueOf(name), durable)); } + public abstract Logger getLogger(); + public boolean isDurable() { return _durable; @@ -194,9 +211,13 @@ public abstract class AbstractExchange implements Exchange, Managable { _exchangeMbean.unregister(); } + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } CurrentActor.get().message(_logSubject, ExchangeMessages.EXH_1002()); - } + } public String toString() { @@ -217,4 +238,54 @@ public abstract class AbstractExchange implements Exchange, Managable { return getVirtualHost().getQueueRegistry(); } + + public boolean isBound(String bindingKey, Map<String,Object> arguments, AMQQueue queue) + { + return isBound(new AMQShortString(bindingKey), queue); + } + + + public boolean isBound(String bindingKey, AMQQueue queue) + { + return isBound(new AMQShortString(bindingKey), queue); + } + + public boolean isBound(String bindingKey) + { + return isBound(new AMQShortString(bindingKey)); + } + + public Exchange getAlternateExchange() + { + return _alternateExchange; + } + + public void setAlternateExchange(Exchange exchange) + { + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } + if(exchange != null) + { + exchange.addReference(this); + } + _alternateExchange = exchange; + + } + + public void removeReference(ExchangeReferrer exchange) + { + _referrers.remove(exchange); + } + + public void addReference(ExchangeReferrer exchange) + { + _referrers.put(exchange, Boolean.TRUE); + } + + public boolean hasReferrers() + { + return !_referrers.isEmpty(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 620799a81f..6b0cf89b95 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -59,6 +59,20 @@ public class DefaultExchangeFactory implements ExchangeFactory return _exchangeClassMap.values(); } + public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) + throws AMQException + { + ExchangeType<? extends Exchange> exchType = _exchangeClassMap.get(new AMQShortString(type)); + if (exchType == null) + { + + throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); + } + Exchange e = exchType.newInstance(_host, (new AMQShortString(exchange)).intern(), durable, 0, autoDelete); + return e; + + } + public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException @@ -92,7 +106,7 @@ public class DefaultExchangeFactory implements ExchangeFactory return; } Class<? extends ExchangeType> exchangeTypeClass = exchangeType.getClass(); - ExchangeType type = exchangeTypeClass.newInstance(); + ExchangeType<? extends ExchangeType> type = exchangeTypeClass.newInstance(); registerExchangeType(type); } catch (ClassCastException classCastEx) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 0ab8208d88..2a8a87be7d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,10 +23,9 @@ package org.apache.qpid.server.exchange; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.protocol.ExchangeInitialiser; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.exchange.ExchangeInitialiser; import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Collection; @@ -41,6 +40,7 @@ public class DefaultExchangeRegistry implements ExchangeRegistry * Maps from exchange name to exchange instance */ private ConcurrentMap<AMQShortString, Exchange> _exchangeMap = new ConcurrentHashMap<AMQShortString, Exchange>(); + private ConcurrentMap<String, Exchange> _exchangeMapStr = new ConcurrentHashMap<String, Exchange>(); private Exchange _defaultExchange; private VirtualHost _host; @@ -57,17 +57,20 @@ public class DefaultExchangeRegistry implements ExchangeRegistry new ExchangeInitialiser().initialise(_host.getExchangeFactory(), this); } - public MessageStore getMessageStore() + + + public DurableConfigurationStore getDurableConfigurationStore() { - return _host.getMessageStore(); + return _host.getDurableConfigurationStore(); } public void registerExchange(Exchange exchange) throws AMQException { _exchangeMap.put(exchange.getName(), exchange); + _exchangeMapStr.put(exchange.getName().toString(), exchange); if (exchange.isDurable()) { - getMessageStore().createExchange(exchange); + getDurableConfigurationStore().createExchange(exchange); } } @@ -90,11 +93,12 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { // TODO: check inUse argument Exchange e = _exchangeMap.remove(name); + _exchangeMapStr.remove(name.toString()); if (e != null) { if (e.isDurable()) { - getMessageStore().removeExchange(e); + getDurableConfigurationStore().removeExchange(e); } e.close(); } @@ -104,6 +108,11 @@ public class DefaultExchangeRegistry implements ExchangeRegistry } } + public void unregisterExchange(String name, boolean inUse) throws AMQException + { + unregisterExchange(new AMQShortString(name), inUse); + } + public Exchange getExchange(AMQShortString name) { if ((name == null) || name.length() == 0) @@ -117,6 +126,19 @@ public class DefaultExchangeRegistry implements ExchangeRegistry } + public Exchange getExchange(String name) + { + if ((name == null) || name.length() == 0) + { + return getDefaultExchange(); + } + else + { + return _exchangeMapStr.get(name); + } + } + + /** * Routes content through exchanges, delivering it to 1 or more queues. * @param payload @@ -134,6 +156,6 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { throw new AMQException("Exchange '" + exchange + "' does not exist"); } - exch.route(payload); + payload.enqueue(exch.route(payload)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index 3567cdff85..4788f96d6c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -40,9 +40,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -149,17 +149,14 @@ public class DirectExchange extends AbstractExchange }// End of MBean class - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new DirectExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } + return new DirectExchangeMBean(); + } + + public Logger getLogger() + { + return _logger; } public AMQShortString getType() @@ -167,8 +164,18 @@ public class DirectExchange extends AbstractExchange return ExchangeDefaults.DIRECT_EXCHANGE_CLASS; } + public void registerQueue(String routingKey, AMQQueue queue, Map<String,Object> args) throws AMQException + { + registerQueue(new AMQShortString(routingKey), queue); + } + public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { + registerQueue(routingKey, queue); + } + + private void registerQueue(AMQShortString routingKey, AMQQueue queue) throws AMQException + { assert queue != null; assert routingKey != null; if (!_index.add(routingKey, queue)) @@ -199,10 +206,11 @@ public class DirectExchange extends AbstractExchange } } - public void route(IncomingMessage payload) throws AMQException + public ArrayList<AMQQueue> route(InboundMessage payload) { - final AMQShortString routingKey = payload.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : payload.getRoutingKey(); + final String routingKey = payload.getRoutingKey(); + final ArrayList<AMQQueue> queues = (routingKey == null) ? null : _index.get(routingKey); @@ -211,7 +219,8 @@ public class DirectExchange extends AbstractExchange _logger.debug("Publishing message to queue " + queues); } - payload.enqueue(queues); + return queues; + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 06209c5458..4bbdeaef1c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -24,20 +24,21 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; -import java.util.List; -import java.util.Map; +import javax.management.JMException; +import java.util.ArrayList; -public interface Exchange +public interface Exchange extends ExchangeReferrer { AMQShortString getName(); AMQShortString getType(); - void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException; + void initialise(VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) + throws AMQException, JMException; boolean isDurable(); @@ -52,9 +53,11 @@ public interface Exchange void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - void route(IncomingMessage message) throws AMQException; + ArrayList<AMQQueue> route(InboundMessage message); /** @@ -93,6 +96,18 @@ public interface Exchange */ boolean hasBindings(); - + boolean isBound(String bindingKey, AMQQueue queue); + + boolean isBound(String bindingKey); + + Exchange getAlternateExchange(); + + void setAlternateExchange(Exchange exchange); + + void removeReference(ExchangeReferrer exchange); + + void addReference(ExchangeReferrer exchange); + + boolean hasReferrers(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index 2f76d41228..b91bf559f1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -38,4 +38,6 @@ public interface ExchangeFactory void initialise(VirtualHostConfiguration hostConfig); Collection<ExchangeType<? extends Exchange>> getRegisteredTypes(); + + Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java index 2abcecb6de..59fe94ddc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ExchangeInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeInitialiser.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,15 +18,11 @@ * under the License. * */ -package org.apache.qpid.server.protocol; +package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeType; public class ExchangeInitialiser { @@ -35,7 +31,7 @@ public class ExchangeInitialiser { define (registry, factory, type.getDefaultExchangeName(), type.getName()); } - + define(registry, factory, ExchangeDefaults.DEFAULT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); registry.setDefaultExchange(registry.getExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME)); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java index 9a98af5689..e41d63d97d 100644..100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ConsumerTagNotUniqueException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeReferrer.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,8 +18,9 @@ * under the License. * */ -package org.apache.qpid.server; -public class ConsumerTagNotUniqueException extends Exception +package org.apache.qpid.server.exchange; + +public interface ExchangeReferrer { } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index fe3b19e74e..e34ef29d9b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -48,4 +48,8 @@ public interface ExchangeRegistry extends MessageRouter Collection<AMQShortString> getExchangeNames(); void initialise() throws AMQException; + + Exchange getExchange(String exchangeName); + + void unregisterExchange(String exchange, boolean ifUnused) throws ExchangeInUseException, AMQException;; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 7fa438587c..00f8ebd856 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -28,9 +28,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -62,7 +62,7 @@ public class FanoutExchange extends AbstractExchange private final class FanoutExchangeMBean extends ExchangeMBean { private static final String BINDING_KEY_SUBSTITUTE = "*"; - + @MBeanConstructor("Creates an MBean for AMQ fanout exchange") public FanoutExchangeMBean() throws JMException { @@ -75,7 +75,7 @@ public class FanoutExchange extends AbstractExchange { _bindingList = new TabularDataSupport(_bindinglistDataType); - + if(_queues.isEmpty()) { return _bindingList; @@ -88,7 +88,7 @@ public class FanoutExchange extends AbstractExchange String queueName = queue.getName().toString(); queueNames.add(queueName); } - + Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; CompositeData bindingData = new CompositeDataSupport(_bindingDataType, COMPOSITE_ITEM_NAMES, bindingItemValues); _bindingList.put(bindingData); @@ -121,17 +121,14 @@ public class FanoutExchange extends AbstractExchange } // End of MBean class - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new FanoutExchange.FanoutExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the direct exchange mbean", ex); - throw new AMQException("Exception occured in creating the direct exchange mbean", ex); - } + return new FanoutExchange.FanoutExchangeMBean(); + } + + public Logger getLogger() + { + return _logger; } public static final ExchangeType<FanoutExchange> TYPE = new ExchangeType<FanoutExchange>() @@ -199,16 +196,16 @@ public class FanoutExchange extends AbstractExchange } } - public void route(IncomingMessage payload) throws AMQException + public ArrayList<AMQQueue> route(InboundMessage payload) { - + if (_logger.isDebugEnabled()) { _logger.debug("Publishing message to queue " + _queues); } - payload.enqueue(new ArrayList(_queues)); + return new ArrayList(_queues); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index 2b7df4361a..35c4a8f9b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.message.AMQMessageHeader; /** * Defines binding and matching based on a set of headers. @@ -87,7 +88,7 @@ class HeadersBinding * Creates a binding for a set of mappings. Those mappings whose value is * null or the empty string are assumed only to be required headers, with * no constraint on the value. Those with a non-null value are assumed to - * define a required match of value. + * define a required match of value. * @param mappings the defined mappings this binding should use */ @@ -139,7 +140,7 @@ class HeadersBinding * @return true if the headers define any required keys and match any required * values */ - public boolean matches(FieldTable headers) + public boolean matches(AMQMessageHeader headers) { if(headers == null) { @@ -151,13 +152,13 @@ class HeadersBinding } } - private boolean and(FieldTable headers) + private boolean and(AMQMessageHeader headers) { - if(headers.keys().containsAll(required)) + if(headers.containsHeaders(required)) { for(Map.Entry<String, Object> e : matches.entrySet()) { - if(!e.getValue().equals(headers.getObject(e.getKey()))) + if(!e.getValue().equals(headers.getHeader(e.getKey()))) { return false; } @@ -171,17 +172,50 @@ class HeadersBinding } - private boolean or(final FieldTable headers) + private boolean or(final AMQMessageHeader headers) { - if(required.isEmpty() || !(Boolean) headers.processOverElements(new RequiredOrProcessor())) + if(required.isEmpty()) { - return ((!matches.isEmpty()) && (Boolean) headers.processOverElements(new MatchesOrProcessor())) - || (required.isEmpty() && matches.isEmpty()); + return matches.isEmpty() || passesMatchesOr(headers); } else { - return true; + if(!passesRequiredOr(headers)) + { + return !matches.isEmpty() && passesMatchesOr(headers); + } + else + { + return true; + } + + } + } + + private boolean passesMatchesOr(AMQMessageHeader headers) + { + for(Map.Entry<String,Object> entry : matches.entrySet()) + { + if(headers.containsHeader(entry.getKey()) + && ((entry.getValue() == null && headers.getHeader(entry.getKey()) == null) + || (entry.getValue().equals(headers.getHeader(entry.getKey()))))) + { + return true; + } + } + return false; + } + + private boolean passesRequiredOr(AMQMessageHeader headers) + { + for(String name : required) + { + if(headers.containsHeader(name)) + { + return true; + } } + return false; } private void processSpecial(String key, Object value) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index c5f5cd05e1..5677cc4510 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -31,9 +31,10 @@ import org.apache.qpid.framing.AMQTypedValue; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.AMQMessageHeader; import javax.management.JMException; import javax.management.openmbean.ArrayType; @@ -50,8 +51,8 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ConcurrentHashMap; /** * An exchange that binds queues based on a set of required headers and header values @@ -82,6 +83,7 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public class HeadersExchange extends AbstractExchange { + private static final Logger _logger = Logger.getLogger(HeadersExchange.class); public static final ExchangeType<HeadersExchange> TYPE = new ExchangeType<HeadersExchange>() @@ -101,6 +103,7 @@ public class HeadersExchange extends AbstractExchange boolean autoDelete) throws AMQException { HeadersExchange exch = new HeadersExchange(); + exch.initialise(host, name, durable, ticket, autoDelete); return exch; } @@ -114,6 +117,7 @@ public class HeadersExchange extends AbstractExchange private final List<Registration> _bindings = new CopyOnWriteArrayList<Registration>(); + private Map<AMQShortString, Registration> _bindingByKey = new ConcurrentHashMap<AMQShortString, Registration>(); /** * HeadersExchangeMBean class implements the management interface for the @@ -208,7 +212,7 @@ public class HeadersExchange extends AbstractExchange { throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" "); } - + if(keyAndValue.length ==1) { //no value was given, only a key. Use an empty value @@ -221,7 +225,7 @@ public class HeadersExchange extends AbstractExchange } } - _bindings.add(new Registration(new HeadersBinding(bindingMap), queue)); + _bindings.add(new Registration(new HeadersBinding(bindingMap), queue, new AMQShortString(binding))); } } // End of MBean class @@ -234,44 +238,48 @@ public class HeadersExchange extends AbstractExchange public void registerQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + " with " + args); - _bindings.add(new Registration(new HeadersBinding(args), queue)); + + Registration registration = new Registration(new HeadersBinding(args), queue, routingKey); + _bindings.add(registration); + } public void deregisterQueue(AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException { _logger.debug("Exchange " + getName() + ": Unbinding " + queue.getName()); - if(!_bindings.remove(new Registration(new HeadersBinding(args), queue))) + + if(!_bindings.remove(new Registration(args == null ? null : new HeadersBinding(args), queue, routingKey))) { throw new AMQException(AMQConstant.NOT_FOUND, "Queue " + queue + " was not registered with exchange " + this.getName() - + " with headers args " + args); + + " with headers args " + args); } } - public void route(IncomingMessage payload) throws AMQException + public ArrayList<AMQQueue> route(InboundMessage payload) { - FieldTable headers = getHeaders(payload.getContentHeaderBody()); + AMQMessageHeader header = payload.getMessageHeader(); if (_logger.isDebugEnabled()) { - _logger.debug("Exchange " + getName() + ": routing message with headers " + headers); + _logger.debug("Exchange " + getName() + ": routing message with headers " + header); } boolean routed = false; ArrayList<AMQQueue> queues = new ArrayList<AMQQueue>(); for (Registration e : _bindings) { - if (e.binding.matches(headers)) + if (e.binding.matches(header)) { if (_logger.isDebugEnabled()) { _logger.debug("Exchange " + getName() + ": delivering message with headers " + - headers + " to " + e.queue.getName()); + header + " to " + e.queue.getName()); } queues.add(e.queue); routed = true; } } - payload.enqueue(queues); + return queues; } public boolean isBound(AMQShortString routingKey, FieldTable arguments, AMQQueue queue) @@ -314,17 +322,9 @@ public class HeadersExchange extends AbstractExchange return ((BasicContentHeaderProperties) contentHeaderFrame.properties).getHeaders(); } - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new HeadersExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the HeadersExchangeMBean", ex); - throw new AMQException("Exception occured in creating the HeadersExchangeMBean", ex); - } + return new HeadersExchangeMBean(); } public Map<AMQShortString, List<AMQQueue>> getBindings() @@ -332,25 +332,38 @@ public class HeadersExchange extends AbstractExchange return null; } + public Logger getLogger() + { + return _logger; + } + + private static class Registration { private final HeadersBinding binding; private final AMQQueue queue; + private final AMQShortString routingKey; - Registration(HeadersBinding binding, AMQQueue queue) + Registration(HeadersBinding binding, AMQQueue queue, AMQShortString routingKey) { this.binding = binding; this.queue = queue; + this.routingKey = routingKey; } public int hashCode() { - return queue.hashCode(); + int queueHash = queue.hashCode(); + int routingHash = routingKey == null ? 0 : routingKey.hashCode(); + return queueHash + routingHash; } public boolean equals(Object o) { - return o instanceof Registration && ((Registration) o).queue.equals(queue); + return o instanceof Registration + && ((Registration) o).queue.equals(queue) + && (routingKey == null ? ((Registration)o).routingKey == null + : routingKey.equals(((Registration)o).routingKey)); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java index ec83161029..90d04c814a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Index.java @@ -39,6 +39,9 @@ class Index { private ConcurrentMap<AMQShortString, ArrayList<AMQQueue>> _index = new ConcurrentHashMap<AMQShortString, ArrayList<AMQQueue>>(); + private ConcurrentMap<String, ArrayList<AMQQueue>> _stringIndex + = new ConcurrentHashMap<String, ArrayList<AMQQueue>>(); + synchronized boolean add(AMQShortString key, AMQQueue queue) { @@ -51,8 +54,10 @@ class Index { queues = new ArrayList<AMQQueue>(queues); } + //next call is atomic, so there is no race to create the list _index.put(key, queues); + _stringIndex.put(key.toString(), queues); if(queues.contains(queue)) { @@ -64,6 +69,8 @@ class Index } } + + synchronized boolean remove(AMQShortString key, AMQQueue queue) { ArrayList<AMQQueue> queues = _index.get(key); @@ -76,10 +83,12 @@ class Index if (queues.size() == 0) { _index.remove(key); + _stringIndex.remove(key.toString()); } else { _index.put(key, queues); + _stringIndex.put(key.toString(), queues); } } return removed; @@ -92,6 +101,12 @@ class Index return _index.get(key); } + ArrayList<AMQQueue> get(String key) + { + return _stringIndex.get(key); + } + + Map<AMQShortString, List<AMQQueue>> getBindingsMap() { return new HashMap<AMQShortString, List<AMQQueue>>(_index); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java index db9beb6da7..025a8014aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/MessageRouter.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,7 +21,6 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.IncomingMessage; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java deleted file mode 100644 index d18ad7ab14..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/NoRouteException.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.exchange; - -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.IncomingMessage; - -/** - * NoRouteException is a {@link RequiredDeliveryException} that represents the failure case where a manadatory message - * cannot be delivered because there is no route for the message. The AMQP status code, 312, is always used to report - * this condition. - * - * <p/><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities <th> Collaborations - * <tr><td> Represent failure to deliver a message that must be delivered. - * </table> - */ -public class NoRouteException extends RequiredDeliveryException -{ - public NoRouteException(String msg, AMQMessage amqMessage) - { - super(msg, amqMessage); - } - - public AMQConstant getReplyCode() - { - return AMQConstant.NO_ROUTE; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 31db1148c6..d5ca5a8a81 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -30,13 +30,13 @@ import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.AMQShortStringTokenizer; -import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.exchange.topic.TopicParser; import org.apache.qpid.server.exchange.topic.TopicMatcherResult; import org.apache.qpid.server.filter.MessageFilter; import org.apache.qpid.server.filter.JMSSelectorFilter; +import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; @@ -111,7 +111,7 @@ public class TopicExchange extends AbstractExchange private final Map<Binding, FieldTable> _bindings = new HashMap<Binding, FieldTable>(); - private final Map<String, WeakReference<JMSSelectorFilter<RuntimeException>>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter<RuntimeException>>>(); + private final Map<String, WeakReference<JMSSelectorFilter>> _selectorCache = new WeakHashMap<String, WeakReference<JMSSelectorFilter>>(); public static class Binding { @@ -162,7 +162,7 @@ public class TopicExchange extends AbstractExchange private final class TopicExchangeResult implements TopicMatcherResult { private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>(); - private final ConcurrentHashMap<AMQQueue, Map<MessageFilter<RuntimeException>,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter<RuntimeException>, Integer>>(); + private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>(); public void addUnfilteredQueue(AMQQueue queue) { @@ -192,12 +192,12 @@ public class TopicExchange extends AbstractExchange } - public void addFilteredQueue(AMQQueue queue, MessageFilter<RuntimeException> filter) + public void addFilteredQueue(AMQQueue queue, MessageFilter filter) { - Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue); + Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); if(filters == null) { - filters = new ConcurrentHashMap<MessageFilter<RuntimeException>,Integer>(); + filters = new ConcurrentHashMap<MessageFilter,Integer>(); _filteredQueues.put(queue, filters); } Integer instances = filters.get(filter); @@ -212,9 +212,9 @@ public class TopicExchange extends AbstractExchange } - public void removeFilteredQueue(AMQQueue queue, MessageFilter<RuntimeException> filter) + public void removeFilteredQueue(AMQQueue queue, MessageFilter filter) { - Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue); + Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); if(filters != null) { Integer instances = filters.get(filter); @@ -228,7 +228,7 @@ public class TopicExchange extends AbstractExchange _filteredQueues.remove(queue); } } - else + else { filters.put(filter, instances - 1); } @@ -239,11 +239,11 @@ public class TopicExchange extends AbstractExchange } public void replaceQueueFilter(AMQQueue queue, - MessageFilter<RuntimeException> oldFilter, - MessageFilter<RuntimeException> newFilter) + MessageFilter oldFilter, + MessageFilter newFilter) { - Map<MessageFilter<RuntimeException>,Integer> filters = _filteredQueues.get(queue); - Map<MessageFilter<RuntimeException>,Integer> newFilters = new ConcurrentHashMap<MessageFilter<RuntimeException>,Integer>(filters); + Map<MessageFilter,Integer> filters = _filteredQueues.get(queue); + Map<MessageFilter,Integer> newFilters = new ConcurrentHashMap<MessageFilter,Integer>(filters); Integer oldFilterInstances = filters.get(oldFilter); if(oldFilterInstances == 1) { @@ -265,7 +265,7 @@ public class TopicExchange extends AbstractExchange _filteredQueues.put(queue,newFilters); } - public Collection<AMQQueue> processMessage(IncomingMessage msg, Collection<AMQQueue> queues) + public Collection<AMQQueue> processMessage(InboundMessage msg, Collection<AMQQueue> queues) { if(queues == null) { @@ -286,11 +286,11 @@ public class TopicExchange extends AbstractExchange queues.addAll(_unfilteredQueues.keySet()); if(!_filteredQueues.isEmpty()) { - for(Map.Entry<AMQQueue, Map<MessageFilter<RuntimeException>, Integer>> entry : _filteredQueues.entrySet()) + for(Map.Entry<AMQQueue, Map<MessageFilter, Integer>> entry : _filteredQueues.entrySet()) { if(!queues.contains(entry.getKey())) { - for(MessageFilter<RuntimeException> filter : entry.getValue().keySet()) + for(MessageFilter filter : entry.getValue().keySet()) { if(filter.matches(msg)) { @@ -443,10 +443,10 @@ public class TopicExchange extends AbstractExchange { result.addUnfilteredQueue(queue); } - _parser.addBinding(routingKey, result); + _parser.addBinding(routingKey, result); _topicExchangeResults.put(routingKey,result); } - else + else { if(argumentsContainSelector(args)) { @@ -463,18 +463,18 @@ public class TopicExchange extends AbstractExchange } - private JMSSelectorFilter<RuntimeException> createSelectorFilter(final FieldTable args) + private JMSSelectorFilter createSelectorFilter(final FieldTable args) throws AMQException { final String selectorString = args.getString(AMQPFilterTypes.JMS_SELECTOR.getValue()); - WeakReference<JMSSelectorFilter<RuntimeException>> selectorRef = _selectorCache.get(selectorString); + WeakReference<JMSSelectorFilter> selectorRef = _selectorCache.get(selectorString); JMSSelectorFilter selector = null; if(selectorRef == null || (selector = selectorRef.get())==null) { - selector = new JMSSelectorFilter<RuntimeException>(selectorString); - _selectorCache.put(selectorString, new WeakReference<JMSSelectorFilter<RuntimeException>>(selector)); + selector = new JMSSelectorFilter(selectorString); + _selectorCache.put(selectorString, new WeakReference<JMSSelectorFilter>(selector)); } return selector; } @@ -490,7 +490,7 @@ public class TopicExchange extends AbstractExchange { routingKey = AMQShortString.EMPTY_STRING; } - + AMQShortStringTokenizer routingTokens = routingKey.tokenize(TOPIC_SEPARATOR); List<AMQShortString> subscriptionList = new ArrayList<AMQShortString>(); @@ -535,10 +535,12 @@ public class TopicExchange extends AbstractExchange return normalizedString; } - public void route(IncomingMessage payload) throws AMQException + public ArrayList<AMQQueue> route(InboundMessage payload) { - final AMQShortString routingKey = payload.getRoutingKey(); + final AMQShortString routingKey = payload.getRoutingKey() == null + ? AMQShortString.EMPTY_STRING + : new AMQShortString(payload.getRoutingKey()); // The copy here is unfortunate, but not too bad relevant to the amount of // things created and copied in getMatchedQueues @@ -550,7 +552,7 @@ public class TopicExchange extends AbstractExchange _logger.info("Message routing key: " + payload.getRoutingKey() + " No routes."); } - payload.enqueue(queues); + return queues; } @@ -572,7 +574,7 @@ public class TopicExchange extends AbstractExchange { return false; } - + } } @@ -640,20 +642,17 @@ public class TopicExchange extends AbstractExchange } - protected ExchangeMBean createMBean() throws AMQException + protected ExchangeMBean createMBean() throws JMException { - try - { - return new TopicExchangeMBean(); - } - catch (JMException ex) - { - _logger.error("Exception occured in creating the topic exchenge mbean", ex); - throw new AMQException("Exception occured in creating the topic exchenge mbean", ex); - } + return new TopicExchangeMBean(); + } + + public Logger getLogger() + { + return _logger; } - private Collection<AMQQueue> getMatchedQueues(IncomingMessage message, AMQShortString routingKey) + private Collection<AMQQueue> getMatchedQueues(InboundMessage message, AMQShortString routingKey) { Collection<TopicMatcherResult> results = _parser.parse(routingKey); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java index a964bce306..2ead9e57af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ArithmeticExpression.java @@ -26,7 +26,7 @@ import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class ArithmeticExpression<E extends Exception> extends BinaryExpression<E> +public abstract class ArithmeticExpression extends BinaryExpression { protected static final int INTEGER = 1; @@ -248,7 +248,7 @@ public abstract class ArithmeticExpression<E extends Exception> extends BinaryEx } } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Object lvalue = left.evaluate(message); if (lvalue == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java index 7308de80d6..024257bea9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BinaryExpression.java @@ -23,23 +23,23 @@ package org.apache.qpid.server.filter; /** * An expression which performs an operation on two expression values. */ -public abstract class BinaryExpression<E extends Exception> implements Expression<E> +public abstract class BinaryExpression implements Expression { - protected Expression<E> left; - protected Expression<E> right; + protected Expression left; + protected Expression right; - public BinaryExpression(Expression<E> left, Expression<E> right) + public BinaryExpression(Expression left, Expression right) { this.left = left; this.right = right; } - public Expression<E> getLeft() + public Expression getLeft() { return left; } - public Expression<E> getRight() + public Expression getRight() { return right; } @@ -90,7 +90,7 @@ public abstract class BinaryExpression<E extends Exception> implements Expressio /** * @param expression */ - public void setRight(Expression<E> expression) + public void setRight(Expression expression) { right = expression; } @@ -98,7 +98,7 @@ public abstract class BinaryExpression<E extends Exception> implements Expressio /** * @param expression */ - public void setLeft(Expression<E> expression) + public void setLeft(Expression expression) { left = expression; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java index 9beb9798d0..06e8664470 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/BooleanExpression.java @@ -20,22 +20,19 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html> // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * A BooleanExpression is an expression that always * produces a Boolean result. */ -public interface BooleanExpression<E extends Exception> extends Expression<E> +public interface BooleanExpression extends Expression { /** * @param message * @return true if the expression evaluates to Boolean.TRUE. - * @throws E */ - public boolean matches(Filterable<E> message) throws E; + public boolean matches(Filterable message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java index 921005c462..f0650cb642 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ComparisonExpression.java @@ -27,22 +27,20 @@ import java.util.HashSet; import java.util.List; import java.util.regex.Pattern; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * A filter performing a comparison of two objects */ -public abstract class ComparisonExpression<E extends Exception> extends BinaryExpression<E> implements BooleanExpression<E> +public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression { - public static<E extends Exception> BooleanExpression<E> createBetween(Expression<E> value, Expression left, Expression<E> right) + public static BooleanExpression createBetween(Expression value, Expression left, Expression right) { return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right)); } - public static<E extends Exception> BooleanExpression<E> createNotBetween(Expression<E> value, Expression<E> left, Expression<E> right) + public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) { return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right)); } @@ -73,7 +71,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx REGEXP_CONTROL_CHARS.add(new Character('!')); } - static class LikeExpression<E extends Exception> extends UnaryExpression<E> implements BooleanExpression<E> + static class LikeExpression extends UnaryExpression implements BooleanExpression { Pattern likePattern; @@ -81,7 +79,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx /** * @param right */ - public LikeExpression(Expression<E> right, String like, int escape) + public LikeExpression(Expression right, String like, int escape) { super(right); @@ -138,7 +136,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx /** * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) */ - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Object rv = this.getRight().evaluate(message); @@ -158,7 +156,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; } - public boolean matches(Filterable<E> message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); @@ -236,7 +234,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx return doCreateEqual(left, right); } - private static<E extends Exception> BooleanExpression<E> doCreateEqual(Expression<E> left, Expression<E> right) + private static BooleanExpression doCreateEqual(Expression left, Expression right) { return new EqualExpression(left, right); } @@ -388,7 +386,7 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx super(left, right); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Comparable lv = (Comparable) left.evaluate(message); if (lv == null) @@ -550,21 +548,21 @@ public abstract class ComparisonExpression<E extends Exception> extends BinaryEx protected abstract boolean asBoolean(int answer); - public boolean matches(Filterable<E> message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } - private static class EqualExpression<E extends Exception> extends ComparisonExpression<E> + private static class EqualExpression extends ComparisonExpression { - public EqualExpression(final Expression<E> left, final Expression<E> right) + public EqualExpression(final Expression left, final Expression right) { super(left, right); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Object lv = left.evaluate(message); Object rv = right.evaluate(message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java index 3ed2286f2e..15cb770216 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/ConstantExpression.java @@ -25,24 +25,22 @@ package org.apache.qpid.server.filter; import java.math.BigDecimal; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * Represents a constant expression */ -public class ConstantExpression<E extends Exception> implements Expression<E> +public class ConstantExpression implements Expression { - static class BooleanConstantExpression<E extends Exception> extends ConstantExpression<E> implements BooleanExpression<E> + static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression { public BooleanConstantExpression(Object value) { super(value); } - public boolean matches(Filterable<E> message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); @@ -121,7 +119,7 @@ public class ConstantExpression<E extends Exception> implements Expression<E> this.value = value; } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { return value; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java index f2ebe41d26..97e9915271 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/Expression.java @@ -20,19 +20,17 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html> // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * Represents an expression */ -public interface Expression<E extends Exception> +public interface Expression { /** * @return the value of this expression */ - public Object evaluate(Filterable<E> message) throws E; + public Object evaluate(Filterable message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java index dd3c126ee5..b5e282038b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -14,26 +14,24 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.filter; // // Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html> // -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; -import org.apache.qpid.AMQException; -public interface FilterManager<E extends Exception> +public interface FilterManager { - void add(MessageFilter<E> filter); + void add(MessageFilter filter); - void remove(MessageFilter<E> filter); + void remove(MessageFilter filter); - boolean allAllow(Filterable<E> msg); + boolean allAllow(Filterable msg); boolean hasFilters(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 4adf5eb9ee..dacd047fea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -26,12 +26,12 @@ import org.apache.qpid.server.filter.jms.selector.SelectorParser; import org.apache.qpid.server.queue.Filterable; -public class JMSSelectorFilter<E extends Exception> implements MessageFilter<E> +public class JMSSelectorFilter implements MessageFilter { private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); private String _selector; - private BooleanExpression<E> _matcher; + private BooleanExpression _matcher; public JMSSelectorFilter(String selector) throws AMQException { @@ -39,7 +39,7 @@ public class JMSSelectorFilter<E extends Exception> implements MessageFilter<E> _matcher = new SelectorParser().parse(selector); } - public boolean matches(Filterable<E> message) throws E + public boolean matches(Filterable message) { boolean match = _matcher.matches(message); if(_logger.isDebugEnabled()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java index 094363ed9a..fdba184da4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/LogicExpression.java @@ -20,22 +20,20 @@ package org.apache.qpid.server.filter; // Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html> // -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; /** * A filter performing a comparison of two objects */ -public abstract class LogicExpression<E extends Exception> extends BinaryExpression<E> implements BooleanExpression<E> +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { - public static<E extends Exception> BooleanExpression createOR(BooleanExpression<E> lvalue, BooleanExpression<E> rvalue) + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { return new OrExpression(lvalue, rvalue); } - public static<E extends Exception> BooleanExpression createAND(BooleanExpression<E> lvalue, BooleanExpression<E> rvalue) + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { return new AndExpression(lvalue, rvalue); } @@ -49,23 +47,23 @@ public abstract class LogicExpression<E extends Exception> extends BinaryExpress super(left, right); } - public abstract Object evaluate(Filterable<E> message) throws E; + public abstract Object evaluate(Filterable message); - public boolean matches(Filterable<E> message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); return (object != null) && (object == Boolean.TRUE); } - private static class OrExpression<E extends Exception> extends LogicExpression<E> + private static class OrExpression extends LogicExpression { - public OrExpression(final BooleanExpression<E> lvalue, final BooleanExpression<E> rvalue) + public OrExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) { super(lvalue, rvalue); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Boolean lv = (Boolean) left.evaluate(message); @@ -86,14 +84,14 @@ public abstract class LogicExpression<E extends Exception> extends BinaryExpress } } - private static class AndExpression<E extends Exception> extends LogicExpression<E> + private static class AndExpression extends LogicExpression { - public AndExpression(final BooleanExpression<E> lvalue, final BooleanExpression<E> rvalue) + public AndExpression(final BooleanExpression lvalue, final BooleanExpression rvalue) { super(lvalue, rvalue); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Boolean lv = (Boolean) left.evaluate(message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index 58fc55f8e6..f5416af09a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -14,17 +14,15 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.filter; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; -public interface MessageFilter<E extends Exception> +public interface MessageFilter { - boolean matches(Filterable<E> message) throws E; + boolean matches(Filterable message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java index 946274f936..11fdeae2b1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/PropertyExpression.java @@ -27,7 +27,6 @@ import java.util.HashMap; import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.server.queue.Filterable; @@ -35,7 +34,7 @@ import org.apache.qpid.server.queue.Filterable; /** * Represents a property expression */ -public class PropertyExpression<E extends Exception> implements Expression<E> +public class PropertyExpression implements Expression { // Constants - defined the same as JMS private static final int NON_PERSISTENT = 1; @@ -44,12 +43,12 @@ public class PropertyExpression<E extends Exception> implements Expression<E> private static final Logger _logger = org.apache.log4j.Logger.getLogger(PropertyExpression.class); - private static final HashMap<String, Expression<? extends Exception>> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression<? extends Exception>>(); + private static final HashMap<String, Expression> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression>(); { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression<E>() + JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() { - public Object evaluate(Filterable<E> message) + public Object evaluate(Filterable message) { //TODO return null; @@ -73,9 +72,9 @@ public class PropertyExpression<E extends Exception> implements Expression<E> JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new ExpirationExpression()); - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression<E>() + JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() { - public Object evaluate(Filterable message) throws E + public Object evaluate(Filterable message) { return message.isRedelivered(); } @@ -83,7 +82,7 @@ public class PropertyExpression<E extends Exception> implements Expression<E> } private final String name; - private final Expression<E> jmsPropertyExpression; + private final Expression jmsPropertyExpression; public boolean outerTest() { @@ -96,10 +95,10 @@ public class PropertyExpression<E extends Exception> implements Expression<E> - jmsPropertyExpression = (Expression<E>) JMS_PROPERTY_EXPRESSIONS.get(name); + jmsPropertyExpression = (Expression) JMS_PROPERTY_EXPRESSIONS.get(name); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { if (jmsPropertyExpression != null) @@ -108,17 +107,7 @@ public class PropertyExpression<E extends Exception> implements Expression<E> } else { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) message.getContentHeaderBody().properties; - - if (_logger.isDebugEnabled()) - { - _logger.debug("Looking up property:" + name); - _logger.debug("Properties are:" + _properties.getHeaders().keySet()); - } - - return _properties.getHeaders().getObject(name); + return message.getMessageHeader().getHeader(name); } } @@ -158,39 +147,30 @@ public class PropertyExpression<E extends Exception> implements Expression<E> } - private static class ReplyToExpression<E extends Exception> implements Expression<E> + private static class ReplyToExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString replyTo = _properties.getReplyTo(); - - return (replyTo == null) ? null : replyTo.toString(); - + String replyTo = message.getMessageHeader().getReplyTo(); + return replyTo; } } - private static class TypeExpression<E extends Exception> implements Expression<E> + private static class TypeExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString type = _properties.getType(); - return (type == null) ? null : type.toString(); + String type = message.getMessageHeader().getType(); + return type; } } - private static class DeliveryModeExpression<E extends Exception> implements Expression<E> + private static class DeliveryModeExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { int mode = message.isPersistent() ? PERSISTENT : NON_PERSISTENT; if (_logger.isDebugEnabled()) @@ -202,68 +182,53 @@ public class PropertyExpression<E extends Exception> implements Expression<E> } } - private static class PriorityExpression<E extends Exception> implements Expression<E> + private static class PriorityExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return (int) _properties.getPriority(); + byte priority = message.getMessageHeader().getPriority(); + return (int) priority; } } - private static class MessageIDExpression<E extends Exception> implements Expression<E> + private static class MessageIDExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString messageId = _properties.getMessageId(); + String messageId = message.getMessageHeader().getMessageId(); - return (messageId == null) ? null : messageId; + return messageId; } } - private static class TimestampExpression<E extends Exception> implements Expression<E> + private static class TimestampExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getTimestamp(); + long timestamp = message.getMessageHeader().getTimestamp(); + return timestamp; } } - private static class CorrelationIdExpression<E extends Exception> implements Expression<E> + private static class CorrelationIdExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - AMQShortString correlationId = _properties.getCorrelationId(); - return (correlationId == null) ? null : correlationId.toString(); + String correlationId = message.getMessageHeader().getCorrelationId(); + + return correlationId; } } - private static class ExpirationExpression<E extends Exception> implements Expression<E> + private static class ExpirationExpression implements Expression { - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { - - CommonContentHeaderProperties _properties = - (CommonContentHeaderProperties) - message.getContentHeaderBody().properties; - - return _properties.getExpiration(); + long expiration = message.getMessageHeader().getExpiration(); + return expiration; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java index b037f57787..c563569cb4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java @@ -26,46 +26,37 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.Filterable; -public class SimpleFilterManager implements FilterManager<AMQException> +public class SimpleFilterManager implements FilterManager { private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); - private final ConcurrentLinkedQueue<MessageFilter<AMQException>> _filters; + private final ConcurrentLinkedQueue<MessageFilter> _filters; private String _toString = ""; public SimpleFilterManager() { _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue<MessageFilter<AMQException>>(); + _filters = new ConcurrentLinkedQueue<MessageFilter>(); } - public void add(MessageFilter<AMQException> filter) + public void add(MessageFilter filter) { _filters.add(filter); updateStringValue(); } - public void remove(MessageFilter<AMQException> filter) + public void remove(MessageFilter filter) { _filters.remove(filter); updateStringValue(); } - public boolean allAllow(Filterable<AMQException> msg) + public boolean allAllow(Filterable msg) { - for (MessageFilter<AMQException> filter : _filters) + for (MessageFilter filter : _filters) { - try + if (!filter.matches(msg)) { - if (!filter.matches(msg)) - { - return false; - } - } - catch (AMQException e) - { - //fixme - e.printStackTrace(); return false; } } @@ -87,7 +78,7 @@ public class SimpleFilterManager implements FilterManager<AMQException> private void updateStringValue() { StringBuilder toString = new StringBuilder(); - for (MessageFilter<AMQException> filter : _filters) + for (MessageFilter filter : _filters) { toString.append(filter.toString()); toString.append(","); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java index 799a38af5a..9e03ecd8bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/UnaryExpression.java @@ -35,18 +35,18 @@ import org.apache.qpid.server.queue.Filterable; /** * An expression which performs an operation on two expression values */ -public abstract class UnaryExpression<E extends Exception> implements Expression<E> +public abstract class UnaryExpression implements Expression { private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); - protected Expression<E> right; + protected Expression right; - public static<E extends Exception> Expression<E> createNegate(Expression<E> left) + public static Expression createNegate(Expression left) { return new NegativeExpression(left); } - public static<E extends Exception> BooleanExpression createInExpression(PropertyExpression<E> right, List elements, final boolean not) + public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) { // Use a HashSet if there are many elements. @@ -69,14 +69,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression return new InExpression(right, inList, not); } - abstract static class BooleanUnaryExpression<E extends Exception> extends UnaryExpression<E> implements BooleanExpression<E> + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { - public BooleanUnaryExpression(Expression<E> left) + public BooleanUnaryExpression(Expression left) { super(left); } - public boolean matches(Filterable<E> message) throws E + public boolean matches(Filterable message) { Object object = evaluate(message); @@ -85,7 +85,7 @@ public abstract class UnaryExpression<E extends Exception> implements Expression } ; - public static<E extends Exception> BooleanExpression<E> createNOT(BooleanExpression<E> left) + public static<E extends Exception> BooleanExpression createNOT(BooleanExpression left) { return new NotExpression(left); } @@ -100,7 +100,7 @@ public abstract class UnaryExpression<E extends Exception> implements Expression return new XQueryExpression(xpath); } - public static<E extends Exception> BooleanExpression createBooleanCast(Expression<E> left) + public static<E extends Exception> BooleanExpression createBooleanCast(Expression left) { return new BooleanCastExpression(left); } @@ -151,7 +151,7 @@ public abstract class UnaryExpression<E extends Exception> implements Expression this.right = left; } - public Expression<E> getRight() + public Expression getRight() { return right; } @@ -204,14 +204,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression */ public abstract String getExpressionSymbol(); - private static class NegativeExpression<E extends Exception> extends UnaryExpression<E> + private static class NegativeExpression extends UnaryExpression { - public NegativeExpression(final Expression<E> left) + public NegativeExpression(final Expression left) { super(left); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Object rvalue = right.evaluate(message); if (rvalue == null) @@ -233,19 +233,19 @@ public abstract class UnaryExpression<E extends Exception> implements Expression } } - private static class InExpression<E extends Exception> extends BooleanUnaryExpression<E> + private static class InExpression extends BooleanUnaryExpression { private final Collection _inList; private final boolean _not; - public InExpression(final PropertyExpression<E> right, final Collection inList, final boolean not) + public InExpression(final PropertyExpression right, final Collection inList, final boolean not) { super(right); _inList = inList; _not = not; } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Object rvalue = right.evaluate(message); @@ -309,14 +309,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression } } - private static class NotExpression<E extends Exception> extends BooleanUnaryExpression<E> + private static class NotExpression extends BooleanUnaryExpression { - public NotExpression(final BooleanExpression<E> left) + public NotExpression(final BooleanExpression left) { super(left); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Boolean lvalue = (Boolean) right.evaluate(message); if (lvalue == null) @@ -333,14 +333,14 @@ public abstract class UnaryExpression<E extends Exception> implements Expression } } - private static class BooleanCastExpression<E extends Exception> extends BooleanUnaryExpression<E> + private static class BooleanCastExpression extends BooleanUnaryExpression { - public BooleanCastExpression(final Expression<E> left) + public BooleanCastExpression(final Expression left) { super(left); } - public Object evaluate(Filterable<E> message) throws E + public Object evaluate(Filterable message) { Object rvalue = right.evaluate(message); if (rvalue == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java index 1311178fb1..aa35cb5a76 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XPathExpression.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.filter; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; import java.lang.reflect.Constructor; @@ -71,7 +70,7 @@ public final class XPathExpression implements BooleanExpression { private final XPathEvaluator evaluator; static public interface XPathEvaluator { - public boolean evaluate(Filterable message) throws AMQException; + public boolean evaluate(Filterable message); } XPathExpression(String xpath) { @@ -93,7 +92,7 @@ public final class XPathExpression implements BooleanExpression { } } - public Object evaluate(Filterable message) throws AMQException { + public Object evaluate(Filterable message) { // try { //FIXME this is flow to disk work // if( message.isDropped() ) @@ -118,7 +117,7 @@ public final class XPathExpression implements BooleanExpression { * @return true if the expression evaluates to Boolean.TRUE. * @throws AMQException */ - public boolean matches(Filterable message) throws AMQException + public boolean matches(Filterable message) { Object object = evaluate(message); return object!=null && object==Boolean.TRUE; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java index c13f81cd08..ae22f17413 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XQueryExpression.java @@ -18,7 +18,6 @@ package org.apache.qpid.server.filter; import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; // @@ -36,23 +35,23 @@ public final class XQueryExpression implements BooleanExpression { this.xpath = xpath; } - public Object evaluate(Filterable message) throws AMQException { + public Object evaluate(Filterable message) { return Boolean.FALSE; } public String toString() { return "XQUERY "+ConstantExpression.encodeString(xpath); } - + /** * @param message * @return true if the expression evaluates to Boolean.TRUE. * @throws AMQException */ - public boolean matches(Filterable message) throws AMQException + public boolean matches(Filterable message) { Object object = evaluate(message); - return object!=null && object==Boolean.TRUE; + return object!=null && object==Boolean.TRUE; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java index cc67776682..f83eb63ac5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/filter/XalanXPathEvaluator.java @@ -27,8 +27,6 @@ import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.Filterable; import org.apache.xpath.CachedXPathAPI; import org.w3c.dom.Document; @@ -36,14 +34,14 @@ import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { - + private final String xpath; public XalanXPathEvaluator(String xpath) { this.xpath = xpath; } - - public boolean evaluate(Filterable m) throws AMQException + + public boolean evaluate(Filterable m) { // TODO - we would have to check the content type and then evaluate the content // here... is this really a feature we wish to implement? - RobG @@ -65,18 +63,18 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(byte[] data) { try { - + InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); - + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder dbuilder = factory.newDocumentBuilder(); Document doc = dbuilder.parse(inputSource); - + CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc,xpath); return iterator.nextNode()!=null; - + } catch (Throwable e) { return false; } @@ -85,12 +83,12 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(String text) { try { InputSource inputSource = new InputSource(new StringReader(text)); - + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder dbuilder = factory.newDocumentBuilder(); Document doc = dbuilder.parse(inputSource); - + // We should associated the cachedXPathAPI object with the message being evaluated // since that should speedup subsequent xpath expressions. CachedXPathAPI cachedXPathAPI = new CachedXPathAPI(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java index 895db7b15b..cfe5aedd61 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java @@ -31,19 +31,28 @@ public abstract class AbstractFlowCreditManager implements FlowCreditManager public final void addStateListener(FlowCreditManagerListener listener) { - _listeners.add(listener); + synchronized(_listeners) + { + _listeners.add(listener); + } } public final boolean removeListener(FlowCreditManagerListener listener) { - return _listeners.remove(listener); + synchronized(_listeners) + { + return _listeners.remove(listener); + } } private void notifyListeners(final boolean suspended) { - for(FlowCreditManagerListener listener : _listeners) + synchronized(_listeners) { - listener.creditStateChanged(!suspended); + for(FlowCreditManagerListener listener : _listeners) + { + listener.creditStateChanged(!suspended); + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java index 96a1071135..c5f2d1e808 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/BytesOnlyCreditManager.java @@ -1,11 +1,8 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Set; -import java.util.HashSet; /* * @@ -36,7 +33,17 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager _bytesCredit = new AtomicLong(initialCredit); } - public void addCredit(long messageCredit, long bytesCredit) + public long getMessageCredit() + { + return -1L; + } + + public long getBytesCredit() + { + return _bytesCredit.get(); + } + + public void restoreCredit(long messageCredit, long bytesCredit) { _bytesCredit.addAndGet(bytesCredit); setSuspended(false); @@ -52,7 +59,7 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager return _bytesCredit.get() > 0L; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(ServerMessage msg) { final long msgSize = msg.getSize(); if(hasCredit()) @@ -74,4 +81,9 @@ public class BytesOnlyCreditManager extends AbstractFlowCreditManager } } + + public void setBytesCredit(long bytesCredit) + { + _bytesCredit.set( bytesCredit ); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java new file mode 100644 index 0000000000..b47f986155 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/CreditCreditManager.java @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.message.ServerMessage; + +public class CreditCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10 +{ + private volatile long _bytesCredit; + private volatile long _messageCredit; + + + public CreditCreditManager() + { + this(0L, 0L); + } + + public CreditCreditManager(long bytesCredit, long messageCredit) + { + _bytesCredit = bytesCredit; + _messageCredit = messageCredit; + setSuspended(!hasCredit()); + + } + + + public synchronized void setCreditLimits(final long bytesCredit, final long messageCredit) + { + _bytesCredit = bytesCredit; + _messageCredit = messageCredit; + + setSuspended(!hasCredit()); + + } + + + public long getMessageCredit() + { + return _messageCredit == -1L + ? Long.MAX_VALUE + : _messageCredit; + } + + public long getBytesCredit() + { + return _bytesCredit == -1L + ? Long.MAX_VALUE + : _bytesCredit; + } + + public synchronized void restoreCredit(final long messageCredit, final long bytesCredit) + { + /*_bytesCredit = 0l; + _messageCredit = 0l; + setSuspended(true);*/ + } + + + public synchronized void addCredit(final long messageCredit, final long bytesCredit) + { + boolean notifyIncrease = true; + if(_messageCredit >= 0L && messageCredit > 0L) + { + notifyIncrease = _messageCredit != 0L; + _messageCredit += messageCredit; + } + + + + if(_bytesCredit >= 0L && bytesCredit > 0L) + { + notifyIncrease = notifyIncrease && bytesCredit>0; + _bytesCredit += bytesCredit; + + + + if(notifyIncrease) + { + notifyIncreaseBytesCredit(); + } + } + + + + setSuspended(!hasCredit()); + + } + + public void clearCredit() + { + _bytesCredit = 0l; + _messageCredit = 0l; + setSuspended(true); + } + + + public synchronized boolean hasCredit() + { + // Note !=, if credit is < 0 that indicates infinite credit + return (_bytesCredit != 0L && _messageCredit != 0L); + } + + public synchronized boolean useCreditForMessage(final ServerMessage msg) + { + if(_messageCredit >= 0L) + { + if(_messageCredit > 0) + { + if(_bytesCredit < 0L) + { + _messageCredit--; + + return true; + } + else if(msg.getSize() <= _bytesCredit) + { + _messageCredit--; + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + else + { + setSuspended(true); + return false; + } + } + else if(_bytesCredit >= 0L) + { + if(msg.getSize() <= _bytesCredit) + { + _bytesCredit -= msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + + } + else + { + return true; + } + + } + + public synchronized void stop() + { + if(_bytesCredit > 0) + { + _bytesCredit = 0; + } + if(_messageCredit > 0) + { + _messageCredit = 0; + } + + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java index a249a6e63a..bec51d361d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -24,6 +24,9 @@ import org.apache.qpid.server.queue.AMQMessage; */ public interface FlowCreditManager { + long getMessageCredit(); + + long getBytesCredit(); public static interface FlowCreditManagerListener { @@ -34,11 +37,10 @@ public interface FlowCreditManager boolean removeListener(FlowCreditManagerListener listener); - public void addCredit(long messageCredit, long bytesCredit); - - public void removeAllCredit(); + public void restoreCredit(long messageCredit, long bytesCredit); public boolean hasCredit(); - public boolean useCreditForMessage(AMQMessage msg); + public boolean useCreditForMessage(ServerMessage msg); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java index cf5e71a6e2..48c336c0b1 100644..100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ConcurrentLinkedQueueNoSize.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/FlowCreditManager_0_10.java @@ -1,3 +1,5 @@ +package org.apache.qpid.server.flow; + /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -7,9 +9,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,21 +20,9 @@ * under the License. * */ -package org.apache.qpid.server.util; - -import java.util.concurrent.ConcurrentLinkedQueue; - -public class ConcurrentLinkedQueueNoSize<E> extends ConcurrentLinkedQueue<E> +public interface FlowCreditManager_0_10 extends FlowCreditManager { - public int size() - { - if (isEmpty()) - { - return 0; - } - else - { - return 1; - } - } + public void addCredit(long count, long bytes); + + void clearCredit(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java index d63431c3eb..901b71fd1f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/LimitlessCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -24,7 +24,17 @@ import org.apache.qpid.server.queue.AMQMessage; */ public class LimitlessCreditManager extends AbstractFlowCreditManager implements FlowCreditManager { - public void addCredit(long messageCredit, long bytesCredit) + public long getMessageCredit() + { + return -1L; + } + + public long getBytesCredit() + { + return -1L; + } + + public void restoreCredit(long messageCredit, long bytesCredit) { } @@ -37,7 +47,7 @@ public class LimitlessCreditManager extends AbstractFlowCreditManager implements return true; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(ServerMessage msg) { return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java index 9c377481de..19a9ac1d23 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageAndBytesCreditManager.java @@ -1,8 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; - -import java.util.concurrent.atomic.AtomicLong; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -29,14 +27,24 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl private long _messageCredit; private long _bytesCredit; - MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) + public MessageAndBytesCreditManager(final long messageCredit, final long bytesCredit) { _messageCredit = messageCredit; _bytesCredit = bytesCredit; } - public synchronized void addCredit(long messageCredit, long bytesCredit) + public synchronized long getMessageCredit() { + return _messageCredit; + } + + public synchronized long getBytesCredit() + { + return _bytesCredit; + } + + public synchronized void restoreCredit(long messageCredit, long bytesCredit) + { _messageCredit += messageCredit; _bytesCredit += bytesCredit; setSuspended(hasCredit()); @@ -54,7 +62,7 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl return (_messageCredit > 0L) && ( _bytesCredit > 0L ); } - public synchronized boolean useCreditForMessage(AMQMessage msg) + public synchronized boolean useCreditForMessage(ServerMessage msg) { if(_messageCredit == 0L) { @@ -76,4 +84,9 @@ public class MessageAndBytesCreditManager extends AbstractFlowCreditManager impl } } + + public synchronized void setBytesCredit(long bytesCredit) + { + _bytesCredit = bytesCredit; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java index c1b3a09006..a386f66b11 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/MessageOnlyCreditManager.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; import java.util.concurrent.atomic.AtomicLong; @@ -33,10 +33,21 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen _messageCredit = new AtomicLong(initialCredit); } - public void addCredit(long messageCredit, long bytesCredit) + public long getMessageCredit() + { + return _messageCredit.get(); + } + + public long getBytesCredit() + { + return -1L; + } + + public void restoreCredit(long messageCredit, long bytesCredit) { - setSuspended(false); _messageCredit.addAndGet(messageCredit); + setSuspended(false); + } public void removeAllCredit() @@ -50,7 +61,7 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen return _messageCredit.get() > 0L; } - public boolean useCreditForMessage(AMQMessage msg) + public boolean useCreditForMessage(ServerMessage msg) { if(hasCredit()) { @@ -73,4 +84,5 @@ public class MessageOnlyCreditManager extends AbstractFlowCreditManager implemen } } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java index be0300f2c1..026804439c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/Pre0_10CreditManager.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.flow; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; public class Pre0_10CreditManager extends AbstractFlowCreditManager implements FlowCreditManager { @@ -81,7 +81,17 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F } - public synchronized void addCredit(final long messageCredit, final long bytesCredit) + public long getMessageCredit() + { + return _messageCredit; + } + + public long getBytesCredit() + { + return _bytesCredit; + } + + public synchronized void restoreCredit(final long messageCredit, final long bytesCredit) { final long messageCreditLimit = _messageCreditLimit; boolean notifyIncrease = true; @@ -123,7 +133,7 @@ public class Pre0_10CreditManager extends AbstractFlowCreditManager implements F && (_messageCreditLimit == 0L || _messageCredit > 0); } - public synchronized boolean useCreditForMessage(final AMQMessage msg) + public synchronized boolean useCreditForMessage(final ServerMessage msg) { if(_messageCreditLimit != 0L) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java new file mode 100644 index 0000000000..10f578551a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/WindowCreditManager.java @@ -0,0 +1,213 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.flow; + +import org.apache.qpid.server.message.ServerMessage; + +public class WindowCreditManager extends AbstractFlowCreditManager implements FlowCreditManager_0_10 +{ + private volatile long _bytesCreditLimit; + private volatile long _messageCreditLimit; + + private volatile long _bytesUsed; + private volatile long _messageUsed; + + public WindowCreditManager() + { + this(0L, 0L); + } + + public WindowCreditManager(long bytesCreditLimit, long messageCreditLimit) + { + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + setSuspended(!hasCredit()); + + } + + + public synchronized void setCreditLimits(final long bytesCreditLimit, final long messageCreditLimit) + { + _bytesCreditLimit = bytesCreditLimit; + _messageCreditLimit = messageCreditLimit; + + setSuspended(!hasCredit()); + + } + + + public long getMessageCredit() + { + return _messageCreditLimit == -1L + ? Long.MAX_VALUE + : _messageUsed < _messageCreditLimit ? _messageCreditLimit - _messageUsed : 0L; + } + + public long getBytesCredit() + { + return _bytesCreditLimit == -1L + ? Long.MAX_VALUE + : _bytesUsed < _bytesCreditLimit ? _bytesCreditLimit - _bytesUsed : 0L; + } + + public synchronized void restoreCredit(final long messageCredit, final long bytesCredit) + { + boolean notifyIncrease = true; + if(_messageCreditLimit > 0L) + { + notifyIncrease = (_messageUsed != _messageCreditLimit); + _messageUsed -= messageCredit; + + //TODO log warning + if(_messageUsed < 0L) + { + _messageUsed = 0; + } + } + + + + if(_bytesCreditLimit > 0L) + { + notifyIncrease = notifyIncrease && bytesCredit>0; + _bytesUsed -= bytesCredit; + + //TODO log warning + if(_bytesUsed < 0L) + { + _bytesUsed = 0; + } + + if(notifyIncrease) + { + notifyIncreaseBytesCredit(); + } + } + + + + setSuspended(!hasCredit()); + + } + + + + public synchronized boolean hasCredit() + { + return (_bytesCreditLimit < 0L || _bytesCreditLimit > _bytesUsed) + && (_messageCreditLimit < 0L || _messageCreditLimit > _messageUsed); + } + + public synchronized boolean useCreditForMessage(final ServerMessage msg) + { + if(_messageCreditLimit >= 0L) + { + if(_messageUsed < _messageCreditLimit) + { + if(_bytesCreditLimit < 0L) + { + _messageUsed++; + + return true; + } + else if(_bytesUsed + msg.getSize() <= _bytesCreditLimit) + { + _messageUsed++; + _bytesUsed += msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + } + else + { + setSuspended(true); + return false; + } + } + else if(_bytesCreditLimit >= 0L) + { + if(_bytesUsed + msg.getSize() <= _bytesCreditLimit) + { + _bytesUsed += msg.getSize(); + + return true; + } + else + { + //setSuspended(true); + return false; + } + + } + else + { + return true; + } + + } + + public void stop() + { + if(_bytesCreditLimit > 0) + { + _bytesCreditLimit = 0; + } + if(_messageCreditLimit > 0) + { + _messageCreditLimit = 0; + } + + } + + public synchronized void addCredit(long count, long bytes) + { + if(bytes > 0) + { + _bytesCreditLimit += bytes; + } + else if(bytes == -1) + { + _bytesCreditLimit = -1; + } + + + if(count > 0) + { + _messageCreditLimit += count; + } + else if(count == -1) + { + _messageCreditLimit = -1; + } + } + + public void clearCredit() + { + _bytesCreditLimit = 0l; + _messageCreditLimit = 0l; + setSuspended(true); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 08610f24cd..859a3477e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -25,7 +25,6 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.Permission; @@ -116,17 +115,31 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic try { - AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(), - body.getArguments(), body.getNoLocal(), body.getExclusive()); - if (!body.getNowait()) + if(consumerTagName == null || channel.getSubscription(consumerTagName) == null) { - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag); - session.writeFrame(responseBody.generateFrame(channelId)); + AMQShortString consumerTag = channel.subscribeToQueue(consumerTagName, queue, !body.getNoAck(), + body.getArguments(), body.getNoLocal(), body.getExclusive()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag); + session.writeFrame(responseBody.generateFrame(channelId)); + + } + } + else + { + AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'"); + + MethodRegistry methodRegistry = session.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + msg, // replytext + body.getClazz(), + body.getMethod()); + session.writeFrame(responseBody.generateFrame(0)); } - } catch (org.apache.qpid.AMQInvalidArgumentException ise) { @@ -141,17 +154,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic } - catch (ConsumerTagNotUniqueException e) - { - AMQShortString msg = new AMQShortString("Non-unique consumer tag, '" + body.getConsumerTag() + "'"); - - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode - msg, // replytext - body.getClazz(), - body.getMethod()); - session.writeFrame(responseBody.generateFrame(0)); - } catch (AMQQueue.ExistingExclusiveSubscription e) { throw body.getChannelException(AMQConstant.ACCESS_REFUSED, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index 001b7858ec..a473184efb 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 @@ -30,6 +30,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.message.AMQMessage;
import org.apache.qpid.server.flow.FlowCreditManager;
import org.apache.qpid.server.flow.MessageOnlyCreditManager;
import org.apache.qpid.server.subscription.SubscriptionImpl;
@@ -40,8 +41,6 @@ import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.queue.SimpleAMQQueue;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -130,8 +129,16 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB throws AMQException
{
singleMessageCredit.useCreditForMessage(entry.getMessage());
- session.getProtocolOutputConverter().writeGetOk(entry.getMessage(), channel.getChannelId(),
- deliveryTag, queue.getMessageCount());
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ session.getProtocolOutputConverter().writeGetOk(entry, channel.getChannelId(),
+ deliveryTag, queue.getMessageCount());
+ }
+ else
+ {
+ //TODO Convert AMQP 0-10 message
+ throw new RuntimeException("Not implemented conversion of 0-10 message");
+ }
}
};
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 fcf3fd4337..62dd76f832 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 @@ -81,13 +81,13 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR message = channel.getUnacknowledgedMessageMap().remove(deliveryTag); if(message != null) { - message.discard(channel.getStoreContext()); + message.discard(); } //sendtoDeadLetterQueue(msg) return; } - if (!message.getMessage().isReferenced()) + if (message.getMessage() == null) { _logger.warn("Message as already been purged, unable to Reject."); return; @@ -96,7 +96,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR if (_logger.isDebugEnabled()) { - _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage().debugIdentity() + + _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage() + ": Requeue:" + body.getRequeue() + //": Resend:" + evt.getMethod().resend + " on channel:" + channel.debugIdentity()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 824f084f57..31bafac0a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -24,7 +24,6 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; @@ -96,7 +95,7 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con session.writeFrame(responseBody.generateFrame(channelId)); - + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java index 0fe8c5dc92..9f392ffc44 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionTuneOkMethodHandler.java @@ -50,5 +50,6 @@ public class ConnectionTuneOkMethodHandler implements StateAwareMethodListener<C } stateManager.changeState(AMQState.CONNECTION_NOT_OPENED); session.initHeartbeats(body.getHeartbeat()); + session.setMaxFrameSize(body.getFrameMax()); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index ba60808492..b0ee5fff08 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -92,11 +92,11 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange try { - exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(), - body.getType() == null ? null : body.getType().intern(), - body.getDurable(), - body.getPassive(), body.getTicket()); - exchangeRegistry.registerExchange(exchange); + exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(), + body.getType() == null ? null : body.getType().intern(), + body.getDurable(), + body.getPassive(), body.getTicket()); + exchangeRegistry.registerExchange(exchange); } catch(AMQUnknownExchangeType e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index b705ea7dba..4f69afe755 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -40,7 +40,7 @@ import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclareBody> @@ -60,11 +60,11 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar public void methodReceived(AMQStateManager stateManager, QueueDeclareBody body, int channelId) throws AMQException { - AMQProtocolSession session = stateManager.getProtocolSession(); + final AMQProtocolSession session = stateManager.getProtocolSession(); VirtualHost virtualHost = session.getVirtualHost(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore store = virtualHost.getMessageStore(); + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); if (!body.getPassive()) @@ -109,11 +109,31 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar else { queue = createQueue(queueName, body, virtualHost, session); + queue.setPrincipalHolder(session); if (queue.isDurable() && !queue.isAutoDelete()) { store.createQueue(queue, body.getArguments()); } queueRegistry.registerQueue(queue); + if(queue.isExclusive() && !queue.isAutoDelete()) + { + final AMQQueue q = queue; + queue.setExclusiveOwner(session); + final AMQProtocolSession.Task sessionCloseTask = new AMQProtocolSession.Task() + { + public void doTask(AMQProtocolSession session) throws AMQException + { + q.setExclusiveOwner(null); + } + }; + session.addSessionCloseTask(sessionCloseTask); + queue.addQueueDeleteTask(new AMQQueue.Task() { + public void doTask(AMQQueue queue) throws AMQException + { + session.removeSessionCloseTask(sessionCloseTask); + } + }); + } if (autoRegister) { Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); @@ -123,14 +143,18 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar } } } - else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) + else if (queue.getPrincipalHolder() != null + && queue.getPrincipalHolder().getPrincipal() != null + && queue.getPrincipalHolder().getPrincipal().getName() != null + && (!queue.getPrincipalHolder().getPrincipal().getName().equals(session.getPrincipal().getName()) + || ((!body.getPassive() && queue.getExclusiveOwner() != null && queue.getExclusiveOwner() != session)))) { throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + queueName + "')," + " as exclusive queue with same name " + "declared on another client ID('" - + queue.getOwner() + "')"); - } + + queue.getPrincipalHolder().getPrincipal().getName() + "')"); + } AMQChannel channel = session.getChannel(channelId); if (channel == null) @@ -197,7 +221,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar } }); }// if exclusive and not durable - + return queue; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index b397db9246..8417492171 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -31,6 +31,7 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.security.access.Permission; @@ -62,7 +63,7 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB AMQProtocolSession session = stateManager.getProtocolSession(); VirtualHost virtualHost = session.getVirtualHost(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - MessageStore store = virtualHost.getMessageStore(); + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); AMQQueue queue; if (body.getQueue() == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java index 2768518f53..3e0f2182b7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -33,7 +33,6 @@ import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.security.access.Permission;
public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBody>
{
@@ -106,7 +105,7 @@ public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBod throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
}
- long purged = queue.clearQueue(channel.getStoreContext());
+ long purged = queue.clearQueue();
if(!body.getNowait())
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java index 9b23d88838..abd2bccc8d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxCommitHandler.java @@ -61,14 +61,12 @@ public class TxCommitHandler implements StateAwareMethodListener<TxCommitBody> { throw body.getChannelNotFoundException(channelId); } - channel.commit(); MethodRegistry methodRegistry = session.getMethodRegistry(); AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); session.writeFrame(responseBody.generateFrame(channelId)); - - channel.processReturns(); + } catch (AMQException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java index 5f402f3fda..4643dee0a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/TxRollbackHandler.java @@ -44,9 +44,9 @@ public class TxRollbackHandler implements StateAwareMethodListener<TxRollbackBod { } - public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, int channelId) throws AMQException + public void methodReceived(AMQStateManager stateManager, TxRollbackBody body, final int channelId) throws AMQException { - AMQProtocolSession session = stateManager.getProtocolSession(); + final AMQProtocolSession session = stateManager.getProtocolSession(); try { @@ -57,17 +57,22 @@ public class TxRollbackHandler implements StateAwareMethodListener<TxRollbackBod throw body.getChannelNotFoundException(channelId); } - channel.rollback(); - MethodRegistry methodRegistry = session.getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody(); - session.writeFrame(responseBody.generateFrame(channelId)); + final MethodRegistry methodRegistry = session.getMethodRegistry(); + final AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody(); + + Runnable task = new Runnable() + { + + public void run() + { + session.writeFrame(responseBody.generateFrame(channelId)); + } + }; + + 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/actors/AMQPChannelActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java index 4a486ae17e..d4d41bc1d4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPChannelActor.java @@ -68,7 +68,7 @@ public class AMQPChannelActor extends AbstractActor */ _logString = "[" + MessageFormat.format(ChannelLogSubject.CHANNEL_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName(), channel.getChannelId()) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java index 432b1d8203..d459fc0f06 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AMQPConnectionActor.java @@ -75,7 +75,7 @@ public class AMQPConnectionActor extends AbstractActor { _logString = "[" + MessageFormat.format(USER_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress()) + "] "; @@ -105,7 +105,7 @@ public class AMQPConnectionActor extends AbstractActor */ _logString = "[" + MessageFormat.format(ConnectionLogSubject.CONNECTION_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName()) + "] "; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java index df4da2a79e..3d31a705fe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java @@ -21,6 +21,9 @@ package org.apache.qpid.server.logging.actors; import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogMessage; +import org.apache.qpid.server.logging.RootMessageLogger; import java.util.EmptyStackException; import java.util.Stack; @@ -66,6 +69,8 @@ public class CurrentActor } }; + private static LogActor _defaultActor; + /** * Set a new LogActor to be the Current Actor * <p/> @@ -105,7 +110,12 @@ public class CurrentActor } catch (EmptyStackException ese) { - return null; + return _defaultActor; } } + + public static void setDefault(LogActor defaultActor) + { + _defaultActor = defaultActor; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties index eafcb43cc0..1a2cb7251c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages.properties @@ -61,13 +61,32 @@ MST-1001 = Created : {0} # 0 - path MST-1002 = Store location : {0} MST-1003 = Closed +MST-1004 = Recovery Start +MST-1005 = Recovered {0,number} messages +MST-1006 = Recovery Complete + +#ConfigStore +# 0 - name +CFG-1001 = Created : {0} +# 0 - path +CFG-1002 = Store location : {0} +CFG-1003 = Closed +CFG-1004 = Recovery Start +CFG-1005 = Recovery Complete + +#TransactionLog +# 0 - name +TXN-1001 = Created : {0} +# 0 - path +TXN-1002 = Store location : {0} +TXN-1003 = Closed # 0 - queue name -MST-1004 = Recovery Start[ : {0}] +TXN-1004 = Recovery Start[ : {0}] # 0 - count # 1 - queue count -MST-1005 = Recovered {0,number} messages for queue {1} +TXN-1005 = Recovered {0,number} messages for queue {1} # 0 - queue name -MST-1006 = Recovery Complete[ : {0}] +TXN-1006 = Recovery Complete[ : {0}] #Connection # 0 - Client id @@ -83,12 +102,18 @@ CHN-1003 = Close # 0 - bytes allowed in prefetch # 1 - number of messagse. CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} +# 0 - queue causing flow control +CHN-1005 = Flow Control Enforced (Queue {0}) +CHN-1006 = Flow Control Removed #Queue # 0 - owner # 1 - priority QUE-1001 = Create :[ Owner: {0}][ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] QUE-1002 = Deleted +QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} +QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} + #Exchange # 0 - type @@ -104,4 +129,4 @@ BND-1002 = Deleted SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close # 0 - The current subscription state -SUB-1003 = State : {0}
\ No newline at end of file +SUB-1003 = State : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties index 9169a1a651..1a2cb7251c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/messages/LogMessages_en_US.properties @@ -16,173 +16,7 @@ # specific language governing permissions and limitations # under the License. # -# LogMessages used within the Java Broker as originally defined on the wiki: -# -# http://cwiki.apache.org/confluence/display/qpid/Status+Update+Design#StatusUpdateDesign-InitialStatusMessages -# -# Technical Notes: -# This is a standard Java Properties file so white space is respected at the -# end of the lines. This file is processed in a number of ways. -# 1) ResourceBundle -# This file is loaded through a ResourceBundle named LogMessages. the en_US -# addition to the file is the localisation. Additional localisations can be -# provided and will automatically be selected based on the <locale> value in -# the config.xml. The default is en_US. -# -# 2) MessasgeFormat -# Each entry is prepared with the Java Core MessageFormat methods. Therefore -# most functionality you can do via MessageFormat can be done here: -# -# http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html -# -# The cavet here is that only default String and number FormatTypes can be used. -# This is due to the processing described in 3 below. If support for date, time -# or choice is requried then the GenerateLogMessages class should be updated to -# provide support. -# -# Format Note: -# As mentioned earlier white space in this file is very important. One thing -# in particular to note is the way MessageFormat peforms its replacements. -# The replacement text will totally replace the {xxx} section so there will be -# no addtion of white space or removal e.g. -# MSG = Text----{0}---- -# When given parameter 'Hello' result in text: -# Text----Hello---- -# -# For simple arguments this is expected however when using Style formats then -# it can be a little unexepcted. In particular a common pattern is used for -# number replacements : {0,number,#}. This is used in the Broker to display an -# Integer simply as the Integer with no formating. e.g new Integer(1234567) -# becomes the String "1234567" which is can be contrasted with the pattern -# without a style format field : {0,number} which becomes string "1,234,567". -# -# What you may not expect is that {0,number, #} would produce the String " 1234567" -# note the space after the ',' here /\ has resulted in a space /\ in -# the output. -# -# More details on the SubformatPattern can be found on the API link above. -# -# 3) GenerateLogMessage/Velocity Macro -# This is the first and final stage of processing that this file goes through. -# 1) Class Generation: -# The GenerateLogMessage processes this file and uses the velocity Macro -# to create classes with static methods to perform the logging and give us -# compile time validation. -# -# 2) Property Processing: -# During the class generation the message properties ({x}) are identified -# and used to create the method signature. -# -# 3) Option Processing: -# The Classes perform final formatting of the messages at runtime based on -# optional parameters that are defined within the message. Optional -# paramters are enclosed in square brackets e.g. [optional]. -# -# To provide fixed log messages as required by the Technical Specification: -# http://cwiki.apache.org/confluence/display/qpid/Operational+Logging+-+Status+Update+-+Technical+Specification#OperationalLogging-StatusUpdate-TechnicalSpecification-Howtoprovidefixedlogmessages -# -# This file is processed by Velocity to create a number of classes that contain -# static methods that provide LogMessages in the code to provide compile time -# validation. -# -# For details of what processing is done see GenerateLogMessages. -# -# What a localiser or developer need know is the following: -# -# The Property structure is important is it defines how the class and methods -# will be built. -# -# Class Generation: -# ================= -# -# Each class of messages will be split in to their own <Class>Messages.java -# Currently the following classes are created and are populated with the -# messages that bear their 3-digit type identifier: -# -# Class | Type -# ---------------------|-------- -# Broker | BKR -# ManagementConsole | MNG -# VirtualHost | VHT -# MessageStore | MST -# Connection | CON -# Channel | CHN -# Queue | QUE -# Exchange | EXH -# Binding | BND -# Subscription | SUB -# -# Property Processing: -# ==================== -# -# Each property is then processed by the GenerateLogMessages class to identify -# The number and type of parameters, {x} entries. Parameters are defaulted to -# String types but the use of FormatType number (e.g.{0,number}) will result -# in a Number type being used. These parameters are then used to build the -# method parameter list. e.g: -# Property: -# BRK-1003 = Shuting down : {0} port {1,number,#} -# becomes Method: -# public static LogMessage BRK_1003(String param1, Number param2) -# -# This improves our compile time validation of log message content and -# ensures that change in the message format does not accidentally cause -# erroneous messages. -# -# Option Processing: -# ==================== -# -# Options are identified in the log message as being surrounded by square -# brackets ([ ]). These optional values can themselves contain paramters -# however nesting of options is not permitted. Identification is performed on -# first matchings so give the message: -# Msg = Log Message [option1] [option2] -# Two options will be identifed and enabled to select text 'option1 and -# 'option2'. -# -# The nesting of a options is not supported and will provide -# unexpected results. e.g. Using Message: -# Msg = Log Message [option1 [sub-option2]] -# -# The options will be 'option1 [sub-option2' and 'sub-option2'. The first -# option includes the second option as the nesting is not detected. -# -# The detected options are presented in the method signature as boolean options -# numerically identified by their position in the message. e.g. -# Property: -# CON-1001 = Open : Client ID {0} [: Protocol Version : {1}] -# becomes Method: -# public static LogMessage CON_1001(String param1, String param2, boolean opt1) -# -# The value of 'opt1' will show/hide the option in the message. Note that -# 'param2' is still required however a null value can be used if the optional -# section is not desired. -# -# Again here the importance of white space needs to be highlighted. -# Looking at the QUE-1001 message as an example. The first thought on how this -# would look would be as follows: -# QUE-1001 = Create : Owner: {0} [AutoDelete] [Durable] [Transient] [Priority: {1,number,#}] -# Each option is correctly defined so the text that is defined will appear when -# selected. e.g. 'AutoDelete'. However, what may not be immediately apparent is -# the white space. Using the above definition of QUE-1001 if we were to print -# the message with only the Priority option displayed it would appear as this: -# "Create : Owner: guest Priority: 1" -# Note the spaces here /\ This is because only the text between the brackets -# has been removed. -# -# Each option needs to include white space to correctly format the message. So -# the correct definition of QUE-1001 is as follows: -# QUE-1001 = Create : Owner: {0}[ AutoDelete][ Durable][ Transient][ Priority: {1,number,#}] -# Note that white space is included with each option and there is no extra -# white space between the options. As a result the output with just Priority -# enabled is as follows: -# "Create : Owner: guest Priority: 1" -# -# The final processing that is done in the generation is the conversion of the -# property name. As a '-' is an illegal character in the method name it is -# converted to '_' This processing gives the final method signature as follows: -# <Class>Message.<Type>_<Number>(<parmaters>,<options>) -# +# Default File used for all non-defined locales. #Broker # 0 - Version # 1 = Build @@ -227,13 +61,32 @@ MST-1001 = Created : {0} # 0 - path MST-1002 = Store location : {0} MST-1003 = Closed +MST-1004 = Recovery Start +MST-1005 = Recovered {0,number} messages +MST-1006 = Recovery Complete + +#ConfigStore +# 0 - name +CFG-1001 = Created : {0} +# 0 - path +CFG-1002 = Store location : {0} +CFG-1003 = Closed +CFG-1004 = Recovery Start +CFG-1005 = Recovery Complete + +#TransactionLog +# 0 - name +TXN-1001 = Created : {0} +# 0 - path +TXN-1002 = Store location : {0} +TXN-1003 = Closed # 0 - queue name -MST-1004 = Recovery Start[ : {0}] +TXN-1004 = Recovery Start[ : {0}] # 0 - count # 1 - queue count -MST-1005 = Recovered {0,number} messages for queue {1} +TXN-1005 = Recovered {0,number} messages for queue {1} # 0 - queue name -MST-1006 = Recovery Complete[ : {0}] +TXN-1006 = Recovery Complete[ : {0}] #Connection # 0 - Client id @@ -247,8 +100,9 @@ CHN-1001 = Create CHN-1002 = Flow {0} CHN-1003 = Close # 0 - bytes allowed in prefetch -# 1 - number of messagse. +# 1 - number of messagse. CHN-1004 = Prefetch Size (bytes) {0,number} : Count {1,number} +# 0 - queue causing flow control CHN-1005 = Flow Control Enforced (Queue {0}) CHN-1006 = Flow Control Removed @@ -260,6 +114,7 @@ QUE-1002 = Deleted QUE-1003 = Overfull : Size : {0,number} bytes, Capacity : {1,number} QUE-1004 = Underfull : Size : {0,number} bytes, Resume Capacity : {1,number} + #Exchange # 0 - type # 1 - name @@ -273,4 +128,5 @@ BND-1002 = Deleted #Subscription SUB-1001 = Create[ : Durable][ : Arguments : {0}] SUB-1002 = Close +# 0 - The current subscription state SUB-1003 = State : {0} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java index 1b22de6d01..03afd0b772 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -46,7 +46,7 @@ public class ChannelLogSubject extends AbstractLogSubject // Provide the value for the 4th replacement. setLogStringWithFormat(CHANNEL_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName(), channel.getChannelId()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java index e07dbcda23..65d65a24d2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ConnectionLogSubject.java @@ -41,7 +41,7 @@ public class ConnectionLogSubject extends AbstractLogSubject public ConnectionLogSubject(AMQProtocolSession session) { setLogStringWithFormat(CONNECTION_FORMAT, session.getSessionID(), - session.getAuthorizedID().getName(), + session.getPrincipal().getName(), session.getRemoteAddress(), session.getVirtualHost().getName()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java index 67aee90ba4..d72b8f24ec 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -65,16 +65,9 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana return null; } - public void register() throws AMQException + public void register() throws JMException { - try - { - getManagedObjectRegistry().registerObject(this); - } - catch (JMException e) - { - throw new AMQException("Error registering managed object " + this + ": " + e, e); - } + getManagedObjectRegistry().registerObject(this); } protected ManagedObjectRegistry getManagedObjectRegistry() @@ -98,7 +91,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana { return getObjectInstanceName() + "[" + getType() + "]"; } - + /** * Created the ObjectName as per the JMX Specs @@ -140,7 +133,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana objectName.append(","); objectName.append("version=").append(_version); - + return new ObjectName(objectName.toString()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index aea9ab43ea..92657d7f3c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -54,6 +54,7 @@ import java.lang.reflect.Proxy; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; +import java.net.UnknownHostException; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; @@ -236,8 +237,17 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. */ - final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); - final String hostname = InetAddress.getLocalHost().getHostName(); + final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(port+PORT_EXPORT_OFFSET, csf, ssf, env); + String localHost; + try + { + localHost = InetAddress.getLocalHost().getHostName(); + } + catch(UnknownHostException ex) + { + localHost="127.0.0.1"; + } + final String hostname = localHost; final JMXServiceURL externalUrl = new JMXServiceURL( "service:jmx:rmi://"+hostname+":"+(port+PORT_EXPORT_OFFSET)+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java index 42ea8921a4..de14785fb0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -22,6 +22,7 @@ package org.apache.qpid.server.management; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import javax.management.JMException; import org.apache.qpid.AMQException; @@ -45,7 +46,7 @@ public interface ManagedObject ManagedObject getParentObject(); - void register() throws AMQException; + void register() throws AMQException, JMException; void unregister() throws AMQException; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java new file mode 100644 index 0000000000..b8a36aba58 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java @@ -0,0 +1,329 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.queue.AMQQueue; + + +import java.util.concurrent.atomic.AtomicInteger; +import java.nio.ByteBuffer; + +/** + * A deliverable message. + */ +public class AMQMessage implements ServerMessage +{ + /** Used for debugging purposes. */ + private static final Logger _log = Logger.getLogger(AMQMessage.class); + + private final AtomicInteger _referenceCount = new AtomicInteger(0); + + /** Flag to indicate that this message requires 'immediate' delivery. */ + + private static final byte IMMEDIATE = 0x01; + + /** + * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality + * for messages published with the 'immediate' flag. + */ + + private static final byte DELIVERED_TO_CONSUMER = 0x02; + + private byte _flags = 0; + + private long _expiration; + + private final long _size; + + private Object _sessionIdentifier; + private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); + + private final StoredMessage<MessageMetaData> _handle; + + + public AMQMessage(StoredMessage<MessageMetaData> handle) + { + _handle = handle; + final MessageMetaData metaData = handle.getMetaData(); + _size = metaData.getContentSize(); + final MessagePublishInfo messagePublishInfo = metaData.getMessagePublishInfo(); + + if(messagePublishInfo.isImmediate()) + { + _flags |= IMMEDIATE; + } + } + + + public String debugIdentity() + { + return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; + } + + public void setExpiration(final long expiration) + { + + _expiration = expiration; + + } + + public boolean isReferenced() + { + return _referenceCount.get() > 0; + } + + public MessageMetaData getMessageMetaData() + { + return _handle.getMetaData(); + } + + public ContentHeaderBody getContentHeaderBody() throws AMQException + { + return getMessageMetaData().getContentHeaderBody(); + } + + + + public Long getMessageId() + { + return _handle.getMessageNumber(); + } + + /** + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. + */ + public AMQMessage takeReference() + { + incrementReference(); // _referenceCount.incrementAndGet(); + + return this; + } + + public boolean incrementReference() + { + return incrementReference(1); + } + + /* Threadsafe. Increment the reference count on the message. */ + public boolean incrementReference(int count) + { + + if(_referenceCount.addAndGet(count) <= 0) + { + _referenceCount.addAndGet(-count); + return false; + } + else + { + return true; + } + + } + + /** + * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the + * message store. + * + * + * @throws org.apache.qpid.server.queue.MessageCleanupException when an attempt was made to remove the message from the message store and that + * failed + */ + public void decrementReference() + { + int count = _referenceCount.decrementAndGet(); + + // note that the operation of decrementing the reference count and then removing the message does not + // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after + // the message has been passed to all queues. i.e. we are + // not relying on the all the increments having taken place before the delivery manager decrements. + if (count == 0) + { + // set the reference count way below 0 so that we can detect that the message has been deleted + // this is to guard against the message being spontaneously recreated (from the mgmt console) + // by copying from other queues at the same time as it is being removed. + _referenceCount.set(Integer.MIN_VALUE/2); + + // must check if the handle is null since there may be cases where we decide to throw away a message + // and the handle has not yet been constructed + if (_handle != null) + { + _handle.remove(); + + } + } + else + { + if (count < 0) + { + throw new RuntimeException("Reference count for message id " + debugIdentity() + + " has gone below 0."); + } + } + } + + + /** + * Called selectors to determin if the message has already been sent + * + * @return _deliveredToConsumer + */ + public boolean getDeliveredToConsumer() + { + return (_flags & DELIVERED_TO_CONSUMER) != 0; + } + + public String getRoutingKey() + { + // TODO + return null; + } + + public AMQMessageHeader getMessageHeader() + { + return getMessageMetaData().getMessageHeader(); + } + + public boolean isPersistent() + { + return getMessageMetaData().isPersistent(); + } + + /** + * Called to enforce the 'immediate' flag. + * + * @returns true if the message is marked for immediate delivery but has not been marked as delivered + * to a consumer + */ + public boolean immediateAndNotDelivered() + { + + return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; + + } + + public MessagePublishInfo getMessagePublishInfo() throws AMQException + { + return getMessageMetaData().getMessagePublishInfo(); + } + + public long getArrivalTime() + { + return getMessageMetaData().getArrivalTime(); + } + + /** + * Checks to see if the message has expired. If it has the message is dequeued. + * + * @param queue The queue to check the expiration against. (Currently not used) + * + * @return true if the message has expire + * + * @throws AMQException + */ + public boolean expired(AMQQueue queue) throws AMQException + { + + if (_expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > _expiration); + } + + return false; + } + + /** + * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). + * And for selector efficiency. + */ + public void setDeliveredToConsumer() + { + _flags |= DELIVERED_TO_CONSUMER; + } + + public long getSize() + { + return _size; + + } + + public boolean isImmediate() + { + return (_flags & IMMEDIATE) == IMMEDIATE; + } + + public long getExpiration() + { + return _expiration; + } + + public MessageReference newReference() + { + return new AMQMessageReference(this); + } + + public Long getMessageNumber() + { + return getMessageId(); + } + + + public Object getPublisherIdentifier() + { + //todo store sessionIdentifier/client id with message in store + //Currently the _sessionIdentifier will be null if the message has been + // restored from a message Store + + return _sessionIdentifier; + + } + + public void setClientIdentifier(final Object sessionIdentifier) + { + _sessionIdentifier = sessionIdentifier; + } + + + public String toString() + { + // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + // _taken + " by :" + _takenBySubcription; + + return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; + } + + public int getContent(ByteBuffer buf, int offset) + { + return _handle.getContent(offset, buf); + } + + public StoredMessage<MessageMetaData> getStoredMessage() + { + return _handle; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java new file mode 100644 index 0000000000..6c9311c3de --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import java.util.Set; + +public interface AMQMessageHeader +{ + String getCorrelationId(); + + long getExpiration(); + + String getMessageId(); + + String getMimeType(); + + String getEncoding(); + + byte getPriority(); + + long getTimestamp(); + + String getType(); + + String getReplyTo(); + + Object getHeader(String name); + + boolean containsHeaders(Set<String> names); + + boolean containsHeader(String name); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java index 0b214ca336..940caaefe4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageHandleFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageReference.java @@ -18,29 +18,27 @@ * under the License. * */ -package org.apache.qpid.server.queue; +package org.apache.qpid.server.message; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.queue.MessageCleanupException; -/** - * Constructs a message handle based on the publish body, the content header and the queue to which the message - * has been routed. - * - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class MessageHandleFactory +public class AMQMessageReference extends MessageReference<AMQMessage> { - public AMQMessageHandle createMessageHandle(Long messageId, MessageStore store, boolean persistent) + + public AMQMessageReference(AMQMessage message) + { + super(message); + } + + protected void onReference(AMQMessage message) + { + message.incrementReference(); + } + + protected void onRelease(AMQMessage message) { - // just hardcoded for now - if (persistent) - { - return new WeakReferenceMessageHandle(messageId, store); - } - else - { - return new InMemoryMessageHandle(messageId); - } + message.decrementReference(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java new file mode 100644 index 0000000000..4a1f8dd191 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java @@ -0,0 +1,114 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; + +import java.util.Set; + +public class ContentHeaderBodyAdapter implements AMQMessageHeader +{ + private final ContentHeaderBody _contentHeaderBody; + + public ContentHeaderBodyAdapter(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + private BasicContentHeaderProperties getProperties() + { + return (BasicContentHeaderProperties) _contentHeaderBody.properties; + } + + public String getCorrelationId() + { + return getProperties().getCorrelationIdAsString(); + } + + public long getExpiration() + { + return getProperties().getExpiration(); + } + + public String getMessageId() + { + return getProperties().getMessageIdAsString(); + } + + public String getMimeType() + { + return getProperties().getContentTypeAsString(); + } + + public String getEncoding() + { + return getProperties().getEncodingAsString(); + } + + public byte getPriority() + { + return getProperties().getPriority(); + } + + public long getTimestamp() + { + return getProperties().getTimestamp(); + } + + public String getType() + { + return getProperties().getTypeAsString(); + } + + public String getReplyTo() + { + return getProperties().getReplyToAsString(); + } + + public Object getHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.get(name); + } + + public boolean containsHeaders(Set<String> names) + { + FieldTable ft = getProperties().getHeaders(); + for(String name : names) + { + if(!ft.containsKey(name)) + { + return false; + } + } + return true; + } + + public boolean containsHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.containsKey(name); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java new file mode 100755 index 0000000000..c32f80fc5b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java @@ -0,0 +1,27 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.message; + +public interface EnqueableMessage +{ + Long getMessageNumber(); + boolean isPersistent(); +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java index bdb0707c27..1b3fdb1870 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessageHandle.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java @@ -18,20 +18,20 @@ * under the License. * */ -package org.apache.qpid.server.queue; +package org.apache.qpid.server.message; -import org.apache.qpid.server.store.StoreContext; -public class MockAMQMessageHandle extends InMemoryMessageHandle +import org.apache.qpid.server.queue.Filterable; + +public interface InboundMessage extends Filterable { - public MockAMQMessageHandle(final Long messageId) - { - super(messageId); - } + String getRoutingKey(); + + AMQMessageHeader getMessageHeader(); + + boolean isPersistent(); + + boolean isRedelivered(); - @Override - public long getBodySize(StoreContext store) - { - return 0l; - } + long getSize(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java new file mode 100755 index 0000000000..08a09c4a85 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java @@ -0,0 +1,31 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.message; + +import java.nio.ByteBuffer; + +public interface MessageContentSource +{ + public int getContent(ByteBuffer buf, int offset); + + long getSize(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java new file mode 100644 index 0000000000..b34a8fc470 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -0,0 +1,309 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.EncodingUtils; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.store.StorableMessageMetaData; +import org.apache.qpid.server.store.MessageMetaDataType; +import org.apache.qpid.AMQException; + +import java.nio.ByteBuffer; +import java.util.Set; + +/** + * Encapsulates a publish body and a content header. In the context of the message store these are treated as a + * single unit. + */ +public class MessageMetaData implements StorableMessageMetaData +{ + private MessagePublishInfo _messagePublishInfo; + + private ContentHeaderBody _contentHeaderBody; + + private int _contentChunkCount; + + private long _arrivalTime; + private static final byte MANDATORY_FLAG = 1; + private static final byte IMMEDIATE_FLAG = 2; + public static final MessageMetaDataType.Factory<MessageMetaData> FACTORY = new MetaDataFactory(); + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) + { + this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); + } + + public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) + { + _contentHeaderBody = contentHeaderBody; + _messagePublishInfo = publishBody; + _contentChunkCount = contentChunkCount; + _arrivalTime = arrivalTime; + } + + public int getContentChunkCount() + { + return _contentChunkCount; + } + + public void setContentChunkCount(int contentChunkCount) + { + _contentChunkCount = contentChunkCount; + } + + public ContentHeaderBody getContentHeaderBody() + { + return _contentHeaderBody; + } + + public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) + { + _contentHeaderBody = contentHeaderBody; + } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) + { + _messagePublishInfo = messagePublishInfo; + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public void setArrivalTime(long arrivalTime) + { + _arrivalTime = arrivalTime; + } + + public MessageMetaDataType getType() + { + return MessageMetaDataType.META_DATA_0_8; + } + + public int getStorableSize() + { + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties); + int size = _contentHeaderBody.getSize(); + size += 4; + size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getExchange()); + size += EncodingUtils.encodedShortStringLength(_messagePublishInfo.getRoutingKey()); + size += 1; // flags for immediate/mandatory + size += EncodingUtils.encodedLongLength(); + + return size; + } + + public int writeToBuffer(int offset, ByteBuffer dest) + { + ByteBuffer src = ByteBuffer.allocate((int)getStorableSize()); + + org.apache.mina.common.ByteBuffer minaSrc = org.apache.mina.common.ByteBuffer.wrap(src); + EncodingUtils.writeInteger(minaSrc, _contentHeaderBody.getSize()); + _contentHeaderBody.writePayload(minaSrc); + EncodingUtils.writeShortStringBytes(minaSrc, _messagePublishInfo.getExchange()); + EncodingUtils.writeShortStringBytes(minaSrc, _messagePublishInfo.getRoutingKey()); + byte flags = 0; + if(_messagePublishInfo.isMandatory()) + { + flags |= MANDATORY_FLAG; + } + if(_messagePublishInfo.isImmediate()) + { + flags |= IMMEDIATE_FLAG; + } + EncodingUtils.writeByte(minaSrc, flags); + EncodingUtils.writeLong(minaSrc,_arrivalTime); + src.position(minaSrc.position()); + src.flip(); + src.position(offset); + src = src.slice(); + if(dest.remaining() < src.limit()) + { + src.limit(dest.remaining()); + } + dest.put(src); + + + return src.limit(); + } + + public int getContentSize() + { + return (int) _contentHeaderBody.bodySize; + } + + public boolean isPersistent() + { + BasicContentHeaderProperties properties = (BasicContentHeaderProperties) (_contentHeaderBody.properties); + return properties.getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT; + } + + private static class MetaDataFactory implements MessageMetaDataType.Factory + { + + + public MessageMetaData createMetaData(ByteBuffer buf) + { + try + { + org.apache.mina.common.ByteBuffer minaSrc = org.apache.mina.common.ByteBuffer.wrap(buf); + int size = EncodingUtils.readInteger(minaSrc); + ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(minaSrc, size); + final AMQShortString exchange = EncodingUtils.readAMQShortString(minaSrc); + final AMQShortString routingKey = EncodingUtils.readAMQShortString(minaSrc); + + final byte flags = EncodingUtils.readByte(minaSrc); + long arrivalTime = EncodingUtils.readLong(minaSrc); + + MessagePublishInfo publishBody = + new MessagePublishInfo() + { + + public AMQShortString getExchange() + { + return exchange; + } + + public void setExchange(AMQShortString exchange) + { + } + + public boolean isImmediate() + { + return (flags & IMMEDIATE_FLAG) != 0; + } + + public boolean isMandatory() + { + return (flags & MANDATORY_FLAG) != 0; + } + + public AMQShortString getRoutingKey() + { + return routingKey; + } + }; + return new MessageMetaData(publishBody, chb, 0, arrivalTime); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + }; + + public AMQMessageHeader getMessageHeader() + { + return new MessageHeaderAdapter(); + } + + private final class MessageHeaderAdapter implements AMQMessageHeader + { + private BasicContentHeaderProperties getProperties() + { + return (BasicContentHeaderProperties) getContentHeaderBody().properties; + } + + public String getCorrelationId() + { + return getProperties().getCorrelationIdAsString(); + } + + public long getExpiration() + { + return getProperties().getExpiration(); + } + + public String getMessageId() + { + return getProperties().getMessageIdAsString(); + } + + public String getMimeType() + { + return getProperties().getContentTypeAsString(); + } + + public String getEncoding() + { + return getProperties().getEncodingAsString(); + } + + public byte getPriority() + { + return getProperties().getPriority(); + } + + public long getTimestamp() + { + return getProperties().getTimestamp(); + } + + public String getType() + { + return getProperties().getTypeAsString(); + } + + public String getReplyTo() + { + return getProperties().getReplyToAsString(); + } + + public Object getHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.get(name); + } + + public boolean containsHeaders(Set<String> names) + { + FieldTable ft = getProperties().getHeaders(); + for(String name : names) + { + if(!ft.containsKey(name)) + { + return false; + } + } + return true; + } + + public boolean containsHeader(String name) + { + FieldTable ft = getProperties().getHeaders(); + return ft.containsKey(name); + } + + + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java new file mode 100755 index 0000000000..5a5e2fe5b4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java @@ -0,0 +1,242 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.message; + +import org.apache.qpid.server.store.StorableMessageMetaData; +import org.apache.qpid.server.store.MessageMetaDataType; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageDeliveryMode; +import org.apache.qpid.transport.Struct; +import org.apache.qpid.transport.codec.BBEncoder; +import org.apache.qpid.transport.codec.BBDecoder; + +import java.nio.ByteBuffer; +import java.lang.ref.WeakReference; + +public class MessageMetaData_0_10 implements StorableMessageMetaData +{ + private Header _header; + private DeliveryProperties _deliveryProps; + private MessageProperties _messageProps; + private MessageTransferHeader _messageHeader; + private long _arrivalTime; + private int _bodySize; + private volatile WeakReference<ByteBuffer> _body; + + private static final int ENCODER_SIZE = 1 << 16; + + public static final MessageMetaDataType.Factory<MessageMetaData_0_10> FACTORY = new MetaDataFactory(); + + private volatile ByteBuffer _encoded; + + + public MessageMetaData_0_10(MessageTransfer xfr) + { + this(xfr.getHeader(), xfr.getBodySize(), xfr.getBody(), System.currentTimeMillis()); + } + + private MessageMetaData_0_10(Header header, int bodySize, long arrivalTime) + { + this(header, bodySize, null, arrivalTime); + } + + private MessageMetaData_0_10(Header header, int bodySize, ByteBuffer xfrBody, long arrivalTime) + { + _header = header; + if(_header != null) + { + _deliveryProps = _header.get(DeliveryProperties.class); + _messageProps = _header.get(MessageProperties.class); + } + else + { + _deliveryProps = null; + _messageProps = null; + } + _messageHeader = new MessageTransferHeader(_deliveryProps, _messageProps); + _arrivalTime = arrivalTime; + _bodySize = bodySize; + + + + if(xfrBody == null) + { + _body = null; + } + else + { + ByteBuffer body = ByteBuffer.allocate(_bodySize); + body.put(xfrBody); + body.flip(); + _body = new WeakReference(body); + } + + + } + + + + public MessageMetaDataType getType() + { + return MessageMetaDataType.META_DATA_0_10; + } + + public int getStorableSize() + { + ByteBuffer buf = _encoded; + + if(buf == null) + { + buf = encodeAsBuffer(); + _encoded = buf; + } + + //TODO -- need to add stuff + return buf.limit(); + } + + private ByteBuffer encodeAsBuffer() + { + BBEncoder encoder = new BBEncoder(ENCODER_SIZE); + + encoder.writeInt64(_arrivalTime); + encoder.writeInt32(_bodySize); + Struct[] headers = _header == null ? new Struct[0] : _header.getStructs(); + encoder.writeInt32(headers.length); + + + for(Struct header : headers) + { + encoder.writeStruct32(header); + + } + + ByteBuffer buf = encoder.buffer(); + return buf; + } + + public int writeToBuffer(int offsetInMetaData, ByteBuffer dest) + { + ByteBuffer buf = _encoded; + + if(buf == null) + { + buf = encodeAsBuffer(); + _encoded = buf; + } + + buf = buf.duplicate(); + + buf.position(offsetInMetaData); + + if(dest.remaining() < buf.limit()) + { + buf.limit(dest.remaining()); + } + dest.put(buf); + return buf.limit(); + } + + public int getContentSize() + { + return _bodySize; + } + + public boolean isPersistent() + { + return _deliveryProps == null ? false : _deliveryProps.getDeliveryMode() == MessageDeliveryMode.PERSISTENT; + } + + public String getRoutingKey() + { + return _deliveryProps == null ? null : _deliveryProps.getRoutingKey(); + } + + public AMQMessageHeader getMessageHeader() + { + return _messageHeader; + } + + public long getSize() + { + + return _bodySize; + } + + public boolean isImmediate() + { + return _deliveryProps != null && _deliveryProps.getImmediate(); + } + + public long getExpiration() + { + return _deliveryProps == null ? 0L : _deliveryProps.getExpiration(); + } + + public long getArrivalTime() + { + return _arrivalTime; + } + + public Header getHeader() + { + return _header; + } + + public ByteBuffer getBody() + { + ByteBuffer body = _body == null ? null : _body.get(); + return body; + } + + public void setBody(ByteBuffer body) + { + _body = new WeakReference(body); + } + + private static class MetaDataFactory implements MessageMetaDataType.Factory<MessageMetaData_0_10> + { + public MessageMetaData_0_10 createMetaData(ByteBuffer buf) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(buf); + + long arrivalTime = decoder.readInt64(); + int bodySize = decoder.readInt32(); + int headerCount = decoder.readInt32(); + + Struct[] headers = new Struct[headerCount]; + + for(int i = 0 ; i < headerCount; i++) + { + headers[i] = decoder.readStruct32(); + } + + Header header = new Header(headers); + + return new MessageMetaData_0_10(header, bodySize, arrivalTime); + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java new file mode 100644 index 0000000000..055403ff08 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageReference.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +public abstract class MessageReference<M extends ServerMessage> +{ + + private static final AtomicReferenceFieldUpdater<MessageReference, ServerMessage> _messageUpdater = + AtomicReferenceFieldUpdater.newUpdater(MessageReference.class, ServerMessage.class,"_message"); + + private volatile M _message; + + public MessageReference(M message) + { + _message = message; + onReference(message); + } + + abstract protected void onReference(M message); + + abstract protected void onRelease(M message); + + public M getMessage() + { + return _message; + } + + public void release() + { + M message = (M) _messageUpdater.getAndSet(this,null); + if(message != null) + { + onRelease(message); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java new file mode 100644 index 0000000000..1a75d7ca65 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.MessageDeliveryPriority; + +import java.util.Set; +import java.util.Map; + +class MessageTransferHeader implements AMQMessageHeader +{ + + + public static final String JMS_TYPE = "x-jms-type"; + + private final DeliveryProperties _deliveryProps; + private final MessageProperties _messageProps; + + public MessageTransferHeader(DeliveryProperties deliveryProps, MessageProperties messageProps) + { + _deliveryProps = deliveryProps; + _messageProps = messageProps; + } + + public String getCorrelationId() + { + return _messageProps == null ? null : new String(_messageProps.getCorrelationId()); + } + + public long getExpiration() + { + return _deliveryProps == null ? null : _deliveryProps.getExpiration(); + } + + public String getMessageId() + { + return _messageProps == null ? null : String.valueOf(_messageProps.getMessageId()); + } + + public String getMimeType() + { + return _messageProps == null ? null : _messageProps.getContentType(); + } + + public String getEncoding() + { + return _messageProps == null ? null : _messageProps.getContentEncoding(); + } + + public byte getPriority() + { + MessageDeliveryPriority priority = _deliveryProps == null + ? MessageDeliveryPriority.MEDIUM + : _deliveryProps.getPriority(); + return (byte) priority.getValue(); + } + + public long getTimestamp() + { + return _deliveryProps == null ? 0L : _deliveryProps.getTimestamp(); + } + + public String getType() + { + Object type = getHeader(JMS_TYPE); + return type instanceof String ? (String) type : null; + } + + public String getReplyTo() + { + return _messageProps == null ? null : _messageProps.getReplyTo().toString(); + } + + public Object getHeader(String name) + { + Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders == null ? null : appHeaders.get(name); + } + + public boolean containsHeaders(Set<String> names) + { + Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders != null && appHeaders.keySet().containsAll(names); + + } + + public boolean containsHeader(String name) + { + Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders != null && appHeaders.containsKey(name); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java new file mode 100644 index 0000000000..e866ad5078 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java @@ -0,0 +1,146 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.transport.*; +import org.apache.qpid.server.store.StoredMessage; + +import java.util.concurrent.atomic.AtomicLong; +import java.nio.ByteBuffer; +import java.lang.ref.WeakReference; + + +public class MessageTransferMessage implements InboundMessage, ServerMessage +{ + + + private StoredMessage<MessageMetaData_0_10> _storeMessage; + + + private WeakReference<Session> _sessionRef; + + + public MessageTransferMessage(StoredMessage<MessageMetaData_0_10> storeMessage, WeakReference<Session> sessionRef) + { + + _storeMessage = storeMessage; + _sessionRef = sessionRef; + + } + + private MessageMetaData_0_10 getMetaData() + { + return _storeMessage.getMetaData(); + } + + public String getRoutingKey() + { + return getMetaData().getRoutingKey(); + + } + + public AMQMessageHeader getMessageHeader() + { + return getMetaData().getMessageHeader(); + } + + public boolean isPersistent() + { + return getMetaData().isPersistent(); + } + + + public boolean isRedelivered() + { + // The *Message* is never redelivered, only queue entries are... this is here so that filters + // can run against the message on entry to an exchange + return false; + } + + public long getSize() + { + + return getMetaData().getSize(); + } + + public boolean isImmediate() + { + return getMetaData().isImmediate(); + } + + public long getExpiration() + { + return getMetaData().getExpiration(); + } + + public MessageReference newReference() + { + return new TransferMessageReference(this); + } + + public Long getMessageNumber() + { + return _storeMessage.getMessageNumber(); + } + + public long getArrivalTime() + { + return getMetaData().getArrivalTime(); + } + + public int getContent(ByteBuffer buf, int offset) + { + return _storeMessage.getContent(offset, buf); + } + + public Header getHeader() + { + return getMetaData().getHeader(); + } + + public ByteBuffer getBody() + { + ByteBuffer body = getMetaData().getBody(); + if(body == null) + { + final int size = (int) getSize(); + int pos = 0; + body = ByteBuffer.allocate(size); + + while(pos < size) + { + pos += getContent(body, pos); + } + + body.flip(); + + getMetaData().setBody(body.duplicate()); + } + return body; + } + + public Session getSession() + { + return _sessionRef == null ? null : _sessionRef.get(); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java new file mode 100644 index 0000000000..1ac538c15b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import java.nio.ByteBuffer; + +public interface ServerMessage extends EnqueableMessage, MessageContentSource +{ + String getRoutingKey(); + + AMQMessageHeader getMessageHeader(); + + boolean isPersistent(); + + long getSize(); + + boolean isImmediate(); + + long getExpiration(); + + MessageReference newReference(); + + Long getMessageNumber(); + + long getArrivalTime(); + + public int getContent(ByteBuffer buf, int offset); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java new file mode 100644 index 0000000000..ed189c49c4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/TransferMessageReference.java @@ -0,0 +1,39 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +public class TransferMessageReference extends MessageReference<MessageTransferMessage> +{ + public TransferMessageReference(MessageTransferMessage message) + { + super(message); + } + + protected void onReference(MessageTransferMessage message) + { + + } + + protected void onRelease(MessageTransferMessage message) + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java new file mode 100755 index 0000000000..aded3f3d2a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java @@ -0,0 +1,124 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.output; + +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.MessageDeliveryMode; +import org.apache.qpid.AMQPInvalidClassException; + +import java.util.Map; + +public class HeaderPropertiesConverter +{ + + public static BasicContentHeaderProperties convert(MessageTransferMessage messageTransferMessage) + { + BasicContentHeaderProperties props = new BasicContentHeaderProperties(); + + Header header = messageTransferMessage.getHeader(); + DeliveryProperties deliveryProps = header.get(DeliveryProperties.class); + MessageProperties messageProps = header.get(MessageProperties.class); + + if(deliveryProps != null) + { + if(deliveryProps.hasDeliveryMode()) + { + props.setDeliveryMode((byte)(deliveryProps.getDeliveryMode() == MessageDeliveryMode.PERSISTENT ? BasicContentHeaderProperties.PERSISTENT : BasicContentHeaderProperties.NON_PERSISTENT)); + } + if(deliveryProps.hasExpiration()) + { + props.setExpiration(deliveryProps.getExpiration()); + } + if(deliveryProps.hasPriority()) + { + props.setPriority((byte)deliveryProps.getPriority().getValue()); + } + if(deliveryProps.hasTimestamp()) + { + props.setTimestamp(deliveryProps.getTimestamp()); + } + } + if(messageProps != null) + { + if(messageProps.hasAppId()) + { + props.setAppId(new AMQShortString(messageProps.getAppId())); + } + if(messageProps.hasContentType()) + { + props.setContentType(messageProps.getContentType()); + } + if(messageProps.hasCorrelationId()) + { + props.setCorrelationId(new AMQShortString(messageProps.getCorrelationId())); + } + if(messageProps.hasContentEncoding()) + { + props.setEncoding(messageProps.getContentEncoding()); + } + if(messageProps.hasMessageId()) + { + props.setMessageId(messageProps.getMessageId().toString()); + } + + // TODO Reply-to + + if(messageProps.hasUserId()) + { + props.setUserId(new AMQShortString(messageProps.getUserId())); + } + + if(messageProps.hasApplicationHeaders()) + { + Map<String, Object> appHeaders = messageProps.getApplicationHeaders(); + FieldTable ft = new FieldTable(); + for(Map.Entry<String, Object> entry : appHeaders.entrySet()) + { + try + { + ft.put(new AMQShortString(entry.getKey()), entry.getValue()); + } + catch(AMQPInvalidClassException e) + { + // TODO + // log here, but ignore - just can;t convert + } + } + props.setHeaders(ft); + + } + } + + + + + + + + return props; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java index e01c5aabbf..5300bad613 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/ProtocolOutputConverter.java @@ -26,10 +26,13 @@ */
package org.apache.qpid.server.output;
-import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.message.MessageContentSource;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.AMQException;
public interface ProtocolOutputConverter
@@ -41,16 +44,16 @@ public interface ProtocolOutputConverter ProtocolOutputConverter newInstance(AMQProtocolSession session);
}
- void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException;
- void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException;
+ void writeGetOk(QueueEntry message, int channelId, long deliveryTag, int queueSize) throws AMQException;
byte getProtocolMinorVersion();
byte getProtocolMajorVersion();
- void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource msgContent, int channelId, int replyCode, AMQShortString replyText)
throws AMQException;
void writeFrame(AMQDataBlock block);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java index 2b55d294b5..2cebec373e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -27,28 +27,34 @@ package org.apache.qpid.server.output.amqp0_8;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.mina.common.ByteBuffer;
-
-import java.util.Iterator;
+import java.nio.ByteBuffer;
public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
{
+ private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+
+ private static final ProtocolVersionMethodConverter PROTOCOL_CONVERTER =
+ METHOD_REGISTRY.getProtocolVersionMethodConverter();
public static Factory getInstanceFactory()
{
return new Factory()
{
-
+
public ProtocolOutputConverter newInstance(AMQProtocolSession session)
{
return new ProtocolOutputConverterImpl(session);
@@ -69,71 +75,47 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return _protocolSession;
}
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException
{
- AMQDataBlock deliver = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
-
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
-
-
- final int bodyCount = messageHandle.getBodyCount(storeContext);
+ AMQDataBlock deliver = createEncodedDeliverFrame(entry, channelId, deliveryTag, consumerTag);
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliver);
+ }
- if(bodyCount == 0)
+ private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+ throws AMQException
+ {
+ if(entry.getMessage() instanceof AMQMessage)
{
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
-
- writeFrame(compositeBlock);
+ return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
}
else
{
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
- }
-
-
+ final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+ ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+ chb.bodySize = message.getSize();
+ return chb;
}
-
-
}
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
{
+ AMQDataBlock deliver = createEncodedGetOkFrame(entry, channelId, deliveryTag, queueSize);
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliver);
+ }
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
+ private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody chb, int channelId, AMQDataBlock deliver)
+ throws AMQException
+ {
- AMQDataBlock deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
+ AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, chb);
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
- final int bodyCount = messageHandle.getBodyCount(storeContext);
- if(bodyCount == 0)
+ final int bodySize = (int) message.getSize();
+ if(bodySize == 0)
{
SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
contentHeader);
@@ -141,66 +123,97 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter }
else
{
+ int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+ final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+ ByteBuffer buf = ByteBuffer.allocate(capacity);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
+ int writtenSize = 0;
- AMQDataBlock firstContentBody = new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb));
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf));
AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
writeFrame(compositeBlock);
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
+ while(writtenSize < bodySize)
{
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, getProtocolSession().getMethodRegistry().getProtocolVersionMethodConverter().convertToBody(cb)));
+ buf = java.nio.ByteBuffer.allocate(capacity);
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf)));
}
-
}
-
-
}
- private AMQDataBlock createEncodedDeliverFrame(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ private AMQDataBlock createEncodedDeliverFrame(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException
{
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+
+ final boolean isRedelivered = entry.isRedelivered();
+
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
BasicDeliverBody deliverBody =
- methodRegistry.createBasicDeliverBody(consumerTag,
+ METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey());
+ isRedelivered,
+ exchangeName,
+ routingKey);
+
AMQFrame deliverFrame = deliverBody.generateFrame(channelId);
return deliverFrame;
}
- private AMQDataBlock createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
+ private AMQDataBlock createEncodedGetOkFrame(QueueEntry entry, int channelId, long deliveryTag, int queueSize)
throws AMQException
{
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+
+ final boolean isRedelivered = entry.isRedelivered();
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
BasicGetOkBody getOkBody =
- methodRegistry.createBasicGetOkBody(deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey(),
+ METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+ isRedelivered,
+ exchangeName,
+ routingKey,
queueSize);
AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
@@ -217,54 +230,31 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return getProtocolSession().getProtocolMajorVersion();
}
- private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ private AMQDataBlock createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, int channelId, int replyCode, AMQShortString replyText) throws AMQException
{
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
BasicReturnBody basicReturnBody =
- methodRegistry.createBasicReturnBody(replyCode,
+ METHOD_REGISTRY.createBasicReturnBody(replyCode,
replyText,
- message.getMessagePublishInfo().getExchange(),
- message.getMessagePublishInfo().getRoutingKey());
+ messagePublishInfo.getExchange(),
+ messagePublishInfo.getRoutingKey());
AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
return returnFrame;
}
- public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ public void writeReturn(MessagePublishInfo messagePublishInfo,
+ ContentHeaderBody header,
+ MessageContentSource content,
+ int channelId,
+ int replyCode,
+ AMQShortString replyText)
throws AMQException
{
- AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- message.getContentHeaderBody());
- Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- if (bodyFrameIterator.hasNext())
- {
- AMQDataBlock firstContentBody = bodyFrameIterator.next();
- AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
- }
- else
- {
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
+ AMQDataBlock returnFrame = createEncodedReturnFrame(messagePublishInfo, channelId, replyCode, replyText);
- writeFrame(compositeBlock);
- }
+ writeMessageDelivery(content, header, channelId, returnFrame);
- //
- // Now start writing out the other content bodies
- // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
- //
- while (bodyFrameIterator.hasNext())
- {
- writeFrame(bodyFrameIterator.next());
- }
}
@@ -276,8 +266,7 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
{
- MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
- BasicCancelOkBody basicCancelOkBody = methodRegistry.createBasicCancelOkBody(consumerTag);
+ BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
writeFrame(basicCancelOkBody.generateFrame(channelId));
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java index 65184fe744..319b5cc7bd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java @@ -1,46 +1,48 @@ package org.apache.qpid.server.output.amqp0_9;
-/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-import org.apache.mina.common.ByteBuffer;
-import java.util.Iterator;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.queue.AMQMessageHandle;
-import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.framing.amqp_0_9.BasicGetBodyImpl;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
{
private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
- private static final ProtocolVersionMethodConverter PROTOCOL_METHOD_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
+ private static final ProtocolVersionMethodConverter
+ PROTOCOL_CONVERTER = METHOD_REGISTRY.getProtocolVersionMethodConverter();
public static Factory getInstanceFactory()
@@ -68,20 +70,46 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return _protocolSession;
}
- public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag)
+ public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
throws AMQException
{
- AMQBody deliverBody = createEncodedDeliverFrame(message, channelId, deliveryTag, consumerTag);
- final ContentHeaderBody contentHeaderBody = message.getContentHeaderBody();
+ AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
+ writeMessageDelivery(entry, channelId, deliverBody);
+ }
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
+ private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+ throws AMQException
+ {
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
+ }
+ else
+ {
+ final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+ ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+ chb.bodySize = message.getSize();
+ return chb;
+ }
+ }
- final int bodyCount = messageHandle.getBodyCount(storeContext);
+ private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)
+ throws AMQException
+ {
+ writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);
+ }
+
+ private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)
+ throws AMQException
+ {
- if(bodyCount == 0)
+
+ int bodySize = (int) message.getSize();
+
+ if(bodySize == 0)
{
SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
contentHeaderBody);
@@ -90,101 +118,75 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter }
else
{
+ int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+
+ final int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(capacity);
+ int writtenSize = 0;
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
- AMQBody firstContentBody = PROTOCOL_METHOD_CONVERTER.convertToBody(cb);
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ AMQBody firstContentBody = PROTOCOL_CONVERTER.convertToBody(buf);
- CompositeAMQBodyBlock compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+ CompositeAMQBodyBlock
+ compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
writeFrame(compositeBlock);
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
+ while(writtenSize < bodySize)
{
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
- }
-
+ buf = java.nio.ByteBuffer.allocate(capacity);
+ writtenSize += message.getContent(buf, writtenSize);
+ buf.flip();
+ writeFrame(new AMQFrame(channelId, PROTOCOL_CONVERTER.convertToBody(buf)));
+ }
}
-
}
private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
{
-
+
AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
contentHeaderBody);
return contentHeader;
}
- public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
{
+ AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
+ writeMessageDelivery(entry, channelId, deliver);
+ }
- final AMQMessageHandle messageHandle = message.getMessageHandle();
- final StoreContext storeContext = message.getStoreContext();
-
- AMQFrame deliver = createEncodedGetOkFrame(message, channelId, deliveryTag, queueSize);
+ private AMQBody createEncodedDeliverBody(QueueEntry entry,
+ final long deliveryTag,
+ final AMQShortString consumerTag)
+ throws AMQException
+ {
- AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
- final int bodyCount = messageHandle.getBodyCount(storeContext);
- if(bodyCount == 0)
+ if(entry.getMessage() instanceof AMQMessage)
{
- SmallCompositeAMQDataBlock compositeBlock = new SmallCompositeAMQDataBlock(deliver,
- contentHeader);
- writeFrame(compositeBlock);
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
}
else
{
-
-
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- ContentChunk cb = messageHandle.getContentChunk(storeContext, 0);
-
- AMQDataBlock firstContentBody = new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb));
- AMQDataBlock[] blocks = new AMQDataBlock[]{deliver, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
-
- //
- // Now start writing out the other content bodies
- //
- for(int i = 1; i < bodyCount; i++)
- {
- cb = messageHandle.getContentChunk(storeContext, i);
- writeFrame(new AMQFrame(channelId, PROTOCOL_METHOD_CONVERTER.convertToBody(cb)));
- }
-
-
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
}
-
- }
-
-
- private AMQBody createEncodedDeliverFrame(AMQMessage message, final int channelId, final long deliveryTag, final AMQShortString consumerTag)
- throws AMQException
- {
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
-
-
- final boolean isRedelivered = messageHandle.isRedelivered();
- final AMQShortString exchangeName = pb.getExchange();
- final AMQShortString routingKey = pb.getRoutingKey();
+ final boolean isRedelivered = entry.isRedelivered();
final AMQBody returnBlock = new AMQBody()
{
@@ -237,22 +239,37 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return returnBlock;
}
- private AMQFrame createEncodedGetOkFrame(AMQMessage message, int channelId, long deliveryTag, int queueSize)
+ private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
throws AMQException
{
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- final AMQMessageHandle messageHandle = message.getMessageHandle();
+ final AMQShortString exchangeName;
+ final AMQShortString routingKey;
+
+ if(entry.getMessage() instanceof AMQMessage)
+ {
+ final AMQMessage message = (AMQMessage) entry.getMessage();
+ final MessagePublishInfo pb = message.getMessagePublishInfo();
+ exchangeName = pb.getExchange();
+ routingKey = pb.getRoutingKey();
+ }
+ else
+ {
+ MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+ DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
+ exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+ routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+ }
+ final boolean isRedelivered = entry.isRedelivered();
BasicGetOkBody getOkBody =
METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
- messageHandle.isRedelivered(),
- pb.getExchange(),
- pb.getRoutingKey(),
+ isRedelivered,
+ exchangeName,
+ routingKey,
queueSize);
- AMQFrame getOkFrame = getOkBody.generateFrame(channelId);
- return getOkFrame;
+ return getOkBody;
}
public byte getProtocolMinorVersion()
@@ -265,53 +282,28 @@ public class ProtocolOutputConverterImpl implements ProtocolOutputConverter return getProtocolSession().getProtocolMajorVersion();
}
- private AMQDataBlock createEncodedReturnFrame(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
+ int replyCode,
+ AMQShortString replyText) throws AMQException
{
BasicReturnBody basicReturnBody =
METHOD_REGISTRY.createBasicReturnBody(replyCode,
replyText,
- message.getMessagePublishInfo().getExchange(),
- message.getMessagePublishInfo().getRoutingKey());
- AMQFrame returnFrame = basicReturnBody.generateFrame(channelId);
+ messagePublishInfo.getExchange(),
+ messagePublishInfo.getRoutingKey());
- return returnFrame;
+
+ return basicReturnBody;
}
- public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText)
+ public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
throws AMQException
{
- AMQDataBlock returnFrame = createEncodedReturnFrame(message, channelId, replyCode, replyText);
-
- AMQDataBlock contentHeader = createContentHeaderBlock(channelId, message.getContentHeaderBody());
-
- Iterator<AMQDataBlock> bodyFrameIterator = message.getBodyFrameIterator(getProtocolSession(), channelId);
- //
- // Optimise the case where we have a single content body. In that case we create a composite block
- // so that we can writeDeliver out the deliver, header and body with a single network writeDeliver.
- //
- if (bodyFrameIterator.hasNext())
- {
- AMQDataBlock firstContentBody = bodyFrameIterator.next();
- AMQDataBlock[] blocks = new AMQDataBlock[]{returnFrame, contentHeader, firstContentBody};
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(blocks);
- writeFrame(compositeBlock);
- }
- else
- {
- CompositeAMQDataBlock compositeBlock = new CompositeAMQDataBlock(new AMQDataBlock[]{returnFrame, contentHeader});
- writeFrame(compositeBlock);
- }
+ AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
- //
- // Now start writing out the other content bodies
- // TODO: MINA needs to be fixed so the the pending writes buffer is not unbounded
- //
- while (bodyFrameIterator.hasNext())
- {
- writeFrame(bodyFrameIterator.next());
- }
+ writeMessageDelivery(message, header, channelId, returnFrame);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index a6fcadad0f..04b3e75f8c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -34,6 +34,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicMarkableReference; +import java.util.concurrent.atomic.AtomicBoolean; import javax.management.JMException; import javax.security.sasl.SaslServer; @@ -83,8 +85,8 @@ import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.Sender; @@ -124,7 +126,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private Object _lastSent; - protected boolean _closed; + protected volatile boolean _closed; // maximum number of channels this session should have private long _maxNoOfChannels = 1000; @@ -139,7 +141,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private Principal _authorizedID; private MethodDispatcher _dispatcher; private ProtocolSessionIdentifier _sessionIdentifier; - + // Create a simple ID that increments for ever new Session private final long _sessionID = idGenerator.getAndIncrement(); @@ -152,11 +154,13 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private long _writtenBytes; private long _readBytes; - + private Job _readJob; private Job _writeJob; private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); + private long _maxFrameSize; + private final AtomicBoolean _closing = new AtomicBoolean(false); public ManagedObject getManagedObject() { @@ -167,7 +171,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _stateManager = new AMQStateManager(virtualHostRegistry, this); _networkDriver = driver; - + _codecFactory = new AMQCodecFactory(true, this); _poolReference.acquireExecutorService(); _readJob = new Job(_poolReference, Job.MAX_JOB_EVENTS, true); @@ -178,17 +182,9 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } - private AMQProtocolSessionMBean createMBean() throws AMQException + private AMQProtocolSessionMBean createMBean() throws JMException { - try - { - return new AMQProtocolSessionMBean(this); - } - catch (JMException ex) - { - _logger.error("AMQProtocolSession MBean creation has failed ", ex); - throw new AMQException("AMQProtocolSession MBean creation has failed ", ex); - } + return new AMQProtocolSessionMBean(this); } public long getSessionID() @@ -201,6 +197,21 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _actor; } + public void setMaxFrameSize(long frameMax) + { + _maxFrameSize = frameMax; + } + + public long getMaxFrameSize() + { + return _maxFrameSize; + } + + public boolean isClosing() + { + return _closing.get(); + } + public void received(final ByteBuffer msg) { _lastIoTime = System.currentTimeMillis(); @@ -290,7 +301,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol else { // The channel has been told to close, we don't process any more frames until - // it's closed. + // it's closed. return; } } @@ -545,7 +556,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private void checkForNotification() { int channelsCount = _channelMap.size(); - if (channelsCount >= _maxNoOfChannels) + if (_managedObject != null && channelsCount >= _maxNoOfChannels) { _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); } @@ -560,7 +571,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _maxNoOfChannels = value; } - + public void commitTransactions(AMQChannel channel) throws AMQException { if ((channel != null) && channel.isTransactional()) @@ -576,7 +587,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol channel.rollback(); } } - + /** * Close a specific channel. This will remove any resources used by the channel, including: <ul><li>any queue * subscriptions (this may in turn remove queues if they are auto delete</li> </ul> @@ -676,34 +687,58 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol /** This must be called when the session is _closed in order to free up any resources managed by the session. */ public void closeSession() throws AMQException { - // REMOVE THIS SHOULD NOT BE HERE. - if (CurrentActor.get() == null) - { - CurrentActor.set(_actor); - } - if (!_closed) + if(_closing.compareAndSet(false,true)) { - if (_virtualHost != null) + // REMOVE THIS SHOULD NOT BE HERE. + if (CurrentActor.get() == null) { - _virtualHost.getConnectionRegistry().deregisterConnection(this); + CurrentActor.set(_actor); } - - closeAllChannels(); - if (_managedObject != null) + if (!_closed) { - _managedObject.unregister(); - // Ensure we only do this once. - _managedObject = null; - } + if (_virtualHost != null) + { + _virtualHost.getConnectionRegistry().deregisterConnection(this); + } + + closeAllChannels(); + if (_managedObject != null) + { + _managedObject.unregister(); + // Ensure we only do this once. + _managedObject = null; + } - for (Task task : _taskList) + for (Task task : _taskList) + { + task.doTask(this); + } + + synchronized(this) + { + _closed = true; + notifyAll(); + } + _poolReference.releaseExecutorService(); + CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); + } + } + else + { + synchronized(this) { - task.doTask(this); + while(!_closed) + { + try + { + wait(1000); + } + catch (InterruptedException e) + { + + } + } } - - _closed = true; - _poolReference.releaseExecutorService(); - CurrentActor.get().message(_logSubject, ConnectionMessages.CON_1002()); } } @@ -778,7 +813,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol throw new IllegalArgumentException("Unsupported socket address class: " + address); } } - + public SaslServer getSaslServer() { return _saslServer; @@ -868,8 +903,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _virtualHost.getConnectionRegistry().registerConnection(this); - _managedObject = createMBean(); - _managedObject.register(); + try + { + _managedObject = createMBean(); + _managedObject.register(); + } + catch (JMException e) + { + _logger.error(e); + } } public void addSessionCloseTask(Task task) @@ -881,7 +923,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { _taskList.remove(task); } - + public ProtocolOutputConverter getProtocolOutputConverter() { return _protocolOutputConverter; @@ -900,10 +942,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol return _authorizedID; } + public Principal getPrincipal() + { + return _authorizedID; + } + public SocketAddress getRemoteAddress() { return _networkDriver.getRemoteAddress(); - } + } public SocketAddress getLocalAddress() { @@ -939,7 +986,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void setNetworkDriver(NetworkDriver driver) { - _networkDriver = driver; + _networkDriver = driver; } public void writerIdle() @@ -968,7 +1015,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol MethodRegistry methodRegistry = MethodRegistry.getMethodRegistry(getProtocolVersion()); ConnectionCloseBody closeBody = methodRegistry.createConnectionCloseBody(200,new AMQShortString(throwable.getMessage()),0,0); - + writeFrame(closeBody.generateFrame(0)); _networkDriver.close(); @@ -984,7 +1031,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { // Do nothing } - + public long getReadBytes() { return _readBytes; @@ -1004,7 +1051,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { return _sessionIdentifier; } - + public String getClientVersion() { return (_clientVersion == null) ? null : _clientVersion.toString(); @@ -1022,5 +1069,5 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol } } } - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index b16ed01c79..48dd16a98c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,7 +28,7 @@ import org.apache.qpid.framing.*; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.logging.RootMessageLogger; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -37,12 +37,18 @@ import java.security.Principal; import java.util.List; -public interface AMQProtocolSession extends AMQVersionAwareProtocolSession +public interface AMQProtocolSession extends AMQVersionAwareProtocolSession, PrincipalHolder { long getSessionID(); LogActor getLogActor(); + void setMaxFrameSize(long frameMax); + + long getMaxFrameSize(); + + boolean isClosing(); + public static final class ProtocolSessionIdentifier { private final Object _sessionIdentifier; @@ -201,9 +207,6 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession void setAuthorizedID(Principal authorizedID); - /** @return a Principal that was used to authorized this session */ - Principal getAuthorizedID(); - public java.net.SocketAddress getRemoteAddress(); public MethodRegistry getMethodRegistry(); @@ -224,8 +227,10 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession void commitTransactions(AMQChannel channel) throws AMQException; + void rollbackTransactions(AMQChannel channel) throws AMQException; + List<AMQChannel> getChannels(); void closeIfLingeringClosedChannels(); - + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index 8497c95e26..67c1e51f6e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -133,7 +133,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed public String getAuthorizedId() { - return (_protocolSession.getAuthorizedID() != null ) ? _protocolSession.getAuthorizedID().getName() : null; + return (_protocolSession.getPrincipal() != null ) ? _protocolSession.getPrincipal().getName() : null; } public String getVersion() @@ -227,7 +227,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } - _protocolSession.commitTransactions(channel); + _protocolSession.rollbackTransactions(channel); } catch (AMQException ex) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java new file mode 100755 index 0000000000..78e21a8f14 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java @@ -0,0 +1,366 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionDelegate; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.log4j.Logger; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.Set; + +public class MultiVersionProtocolEngine implements ProtocolEngine +{ + private static final Logger _logger = Logger.getLogger(MultiVersionProtocolEngine.class); + + + + private NetworkDriver _networkDriver; + private Set<VERSION> _supported; + private String _fqdn; + private IApplicationRegistry _appRegistry; + + private volatile ProtocolEngine _delegate = new SelfDelegateProtocolEngine(); + + public MultiVersionProtocolEngine(IApplicationRegistry appRegistry, + String fqdn, + Set<VERSION> supported, NetworkDriver networkDriver) + { + _appRegistry = appRegistry; + _fqdn = fqdn; + _supported = supported; + _networkDriver = networkDriver; + } + + public void setNetworkDriver(NetworkDriver driver) + { + _delegate.setNetworkDriver(driver); + } + + public SocketAddress getRemoteAddress() + { + return _delegate.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _delegate.getLocalAddress(); + } + + public long getWrittenBytes() + { + return _delegate.getWrittenBytes(); + } + + public long getReadBytes() + { + return _delegate.getReadBytes(); + } + + public void closed() + { + _delegate.closed(); + } + + public void writerIdle() + { + _delegate.writerIdle(); + } + + public void readerIdle() + { + _delegate.readerIdle(); + } + + public void received(ByteBuffer msg) + { + _delegate.received(msg); + } + + public void exception(Throwable t) + { + _delegate.exception(t); + } + + private static final int MINIMUM_REQUIRED_HEADER_BYTES = 8; + + private static final byte[] AMQP_0_8_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 8, + (byte) 0 + }; + + private static final byte[] AMQP_0_9_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 0, + (byte) 9 + }; + +private static final byte[] AMQP_0_9_1_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 0, + (byte) 9, + (byte) 1 + }; + + + private static final byte[] AMQP_0_10_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 0, + (byte) 10 + }; + + private static interface DelegateCreator + { + VERSION getVersion(); + byte[] getHeaderIdentifier(); + ProtocolEngine getProtocolEngine(); + } + + private DelegateCreator creator_0_8 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_8; + } + + public byte[] getHeaderIdentifier() + { + return AMQP_0_8_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver); + } + }; + + private DelegateCreator creator_0_9 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_9; + } + + + public byte[] getHeaderIdentifier() + { + return AMQP_0_9_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver); + } + }; + + private DelegateCreator creator_0_9_1 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_9_1; + } + + + public byte[] getHeaderIdentifier() + { + return AMQP_0_9_1_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + return new AMQProtocolEngine(_appRegistry.getVirtualHostRegistry(), _networkDriver); + } + }; + + + private DelegateCreator creator_0_10 = new DelegateCreator() + { + + public VERSION getVersion() + { + return VERSION.v0_10; + } + + + public byte[] getHeaderIdentifier() + { + return AMQP_0_10_HEADER; + } + + public ProtocolEngine getProtocolEngine() + { + final ConnectionDelegate connDelegate = + new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn); + + Connection conn = new ServerConnection(); + conn.setConnectionDelegate(connDelegate); + + return new ProtocolEngine_0_10( conn, _networkDriver); + } + }; + + private final DelegateCreator[] _creators = + new DelegateCreator[] { creator_0_8, creator_0_9, creator_0_9_1, creator_0_10 }; + + + private class SelfDelegateProtocolEngine implements ProtocolEngine + { + + private final ByteBuffer _header = ByteBuffer.allocate(MINIMUM_REQUIRED_HEADER_BYTES); + + public void setNetworkDriver(NetworkDriver driver) + { + _networkDriver = driver; + } + + public SocketAddress getRemoteAddress() + { + return _networkDriver.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _networkDriver.getLocalAddress(); + } + + public long getWrittenBytes() + { + return 0; + } + + public long getReadBytes() + { + return 0; + } + + public void received(ByteBuffer msg) + { + ByteBuffer msgheader = msg.duplicate(); + if(_header.remaining() > msgheader.limit()) + { + msg.position(msg.limit()); + } + else + { + msgheader.limit(_header.remaining()); + msg.position(_header.remaining()); + } + + _header.put(msgheader); + + if(!_header.hasRemaining()) + { + _header.flip(); + byte[] headerBytes = new byte[MINIMUM_REQUIRED_HEADER_BYTES]; + _header.get(headerBytes); + + + ProtocolEngine newDelegate = null; + + for(int i = 0; newDelegate == null && i < _creators.length; i++) + { + + if(_supported.contains(_creators[i].getVersion())) + { + byte[] compareBytes = _creators[i].getHeaderIdentifier(); + boolean equal = true; + for(int j = 0; equal && j<compareBytes.length; j++) + { + equal = headerBytes[j] == compareBytes[j]; + } + if(equal) + { + newDelegate = _creators[i].getProtocolEngine(); + } + + + } + } + // let the first delegate handle completely unknown versions + if(newDelegate == null) + { + newDelegate = _creators[0].getProtocolEngine(); + } + newDelegate.setNetworkDriver(_networkDriver); + + _delegate = newDelegate; + + _header.flip(); + _delegate.received(_header); + if(msg.hasRemaining()) + { + _delegate.received(msg); + } + + } + + } + + public void exception(Throwable t) + { + _logger.error("Error establishing session", t); + } + + public void closed() + { + + } + + public void writerIdle() + { + + } + + public void readerIdle() + { + + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java new file mode 100755 index 0000000000..75358c42d9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactory.java @@ -0,0 +1,75 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngineFactory; +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; + +import java.util.Set; +import java.util.Arrays; +import java.util.HashSet; + +public class MultiVersionProtocolEngineFactory implements ProtocolEngineFactory +{ + ; + + + public enum VERSION { v0_8, v0_9, v0_9_1, v0_10 }; + + private static final Set<VERSION> ALL_VERSIONS = new HashSet<VERSION>(Arrays.asList(VERSION.values())); + + private final IApplicationRegistry _appRegistry; + private final String _fqdn; + private final Set<VERSION> _supported; + + + public MultiVersionProtocolEngineFactory() + { + this(1, "localhost", ALL_VERSIONS); + } + + public MultiVersionProtocolEngineFactory(String fqdn, Set<VERSION> versions) + { + this(1, fqdn, versions); + } + + + public MultiVersionProtocolEngineFactory(String fqdn) + { + this(1, fqdn, ALL_VERSIONS); + } + + public MultiVersionProtocolEngineFactory(int instance, String fqdn, Set<VERSION> supportedVersions) + { + _appRegistry = ApplicationRegistry.getInstance(instance); + _fqdn = fqdn; + _supported = supportedVersions; + } + + + public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) + { + return new MultiVersionProtocolEngine(_appRegistry, _fqdn, _supported, networkDriver); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java new file mode 100755 index 0000000000..7c3adf8b7d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngineFactory_0_10.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngineFactory; +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionDelegate; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.qpid.server.protocol.ProtocolEngine_0_10; + +public class ProtocolEngineFactory_0_10 implements ProtocolEngineFactory +{ + private ConnectionDelegate _delegate; + + public ProtocolEngineFactory_0_10(ConnectionDelegate delegate) + { + _delegate = delegate; + } + + public ProtocolEngine newProtocolEngine(NetworkDriver networkDriver) + { + Connection conn = new ServerConnection(); + conn.setConnectionDelegate(_delegate); + return new ProtocolEngine_0_10(conn, networkDriver); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java new file mode 100755 index 0000000000..e3cd3acd98 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_0_10.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.protocol; + +import org.apache.qpid.protocol.ProtocolEngine; +import org.apache.qpid.transport.NetworkDriver; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.network.InputHandler; +import org.apache.qpid.transport.network.Assembler; +import org.apache.qpid.transport.network.Disassembler; + +import java.net.SocketAddress; + +public class ProtocolEngine_0_10 extends InputHandler implements ProtocolEngine +{ + public static final int MAX_FRAME_SIZE = 64 * 1024 - 1; + + private NetworkDriver _networkDriver; + private long _readBytes; + private long _writtenBytes; + private Connection _connection; + + public ProtocolEngine_0_10(Connection conn, NetworkDriver networkDriver) + { + super(new Assembler(conn)); + _connection = conn; + _networkDriver = networkDriver; + } + + public void setNetworkDriver(NetworkDriver driver) + { + _networkDriver = driver; + Disassembler dis = new Disassembler(driver, MAX_FRAME_SIZE); + _connection.setSender(dis); + } + + public SocketAddress getRemoteAddress() + { + return _networkDriver.getRemoteAddress(); + } + + public SocketAddress getLocalAddress() + { + return _networkDriver.getLocalAddress(); + } + + public long getReadBytes() + { + return _readBytes; + } + + public long getWrittenBytes() + { + return _writtenBytes; + } + + public void writerIdle() + { + //Todo + } + + public void readerIdle() + { + //Todo + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java deleted file mode 100644 index b987dae16d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ /dev/null @@ -1,502 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.TransactionalContext; - - -import java.util.Iterator; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A deliverable message. - */ -public class AMQMessage implements Filterable<AMQException> -{ - /** Used for debugging purposes. */ - private static final Logger _log = Logger.getLogger(AMQMessage.class); - - private final AtomicInteger _referenceCount = new AtomicInteger(1); - - private final AMQMessageHandle _messageHandle; - - /** Holds the transactional context in which this message is being processed. */ - private StoreContext _storeContext; - - /** Flag to indicate that this message requires 'immediate' delivery. */ - - private static final byte IMMEDIATE = 0x01; - - /** - * Flag to indicate whether this message has been delivered to a consumer. Used in implementing return functionality - * for messages published with the 'immediate' flag. - */ - - private static final byte DELIVERED_TO_CONSUMER = 0x02; - - private byte _flags = 0; - - private long _expiration; - - private final long _size; - - private AMQProtocolSession.ProtocolSessionIdentifier _sessionIdentifier; - private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - - - - /** - * Used to iterate through all the body frames associated with this message. Will not keep all the data in memory - * therefore is memory-efficient. - */ - private class BodyFrameIterator implements Iterator<AMQDataBlock> - { - private int _channel; - - private int _index = -1; - private AMQProtocolSession _protocolSession; - - private BodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - _channel = channel; - _protocolSession = protocolSession; - } - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); - } - catch (AMQException e) - { - _log.error("Unable to get body count: " + e, e); - - return false; - } - } - - public AMQDataBlock next() - { - try - { - - AMQBody cb = - getProtocolVersionMethodConverter().convertToBody(_messageHandle.getContentChunk(getStoreContext(), - ++_index)); - - return new AMQFrame(_channel, cb); - } - catch (AMQException e) - { - // have no choice but to throw a runtime exception - throw new RuntimeException("Error getting content body: " + e, e); - } - - } - - private ProtocolVersionMethodConverter getProtocolVersionMethodConverter() - { - return _protocolSession.getMethodRegistry().getProtocolVersionMethodConverter(); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - public void clearStoreContext() - { - _storeContext = new StoreContext(); - } - - public StoreContext getStoreContext() - { - return _storeContext; - } - - private class BodyContentIterator implements Iterator<ContentChunk> - { - - private int _index = -1; - - public boolean hasNext() - { - try - { - return _index < (_messageHandle.getBodyCount(getStoreContext()) - 1); - } - catch (AMQException e) - { - _log.error("Error getting body count: " + e, e); - - return false; - } - } - - public ContentChunk next() - { - try - { - return _messageHandle.getContentChunk(getStoreContext(), ++_index); - } - catch (AMQException e) - { - throw new RuntimeException("Error getting content body: " + e, e); - } - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageId - * @param store - * @param factory - * - * @throws AMQException - */ - public AMQMessage(Long messageId, MessageStore store, MessageHandleFactory factory, TransactionalContext txnConext) - throws AMQException - { - _messageHandle = factory.createMessageHandle(messageId, store, true); - _storeContext = txnConext.getStoreContext(); - _size = _messageHandle.getBodySize(txnConext.getStoreContext()); - } - - /** - * Used when recovering, i.e. when the message store is creating references to messages. In that case, the normal - * enqueue/routingComplete is not done since the recovery process is responsible for routing the messages to - * queues. - * - * @param messageHandle - * - * @throws AMQException - */ - public AMQMessage( - AMQMessageHandle messageHandle, - StoreContext storeConext, - MessagePublishInfo info) - throws AMQException - { - _messageHandle = messageHandle; - _storeContext = storeConext; - - if(info.isImmediate()) - { - _flags |= IMMEDIATE; - } - _size = messageHandle.getBodySize(storeConext); - - } - - - protected AMQMessage(AMQMessage msg) throws AMQException - { - _messageHandle = msg._messageHandle; - _storeContext = msg._storeContext; - _flags = msg._flags; - _size = msg._size; - - } - - - public String debugIdentity() - { - return "(HC:" + System.identityHashCode(this) + " ID:" + getMessageId() + " Ref:" + _referenceCount.get() + ")"; - } - - public void setExpiration(final long expiration) - { - - _expiration = expiration; - - } - - public boolean isReferenced() - { - return _referenceCount.get() > 0; - } - - public Iterator<AMQDataBlock> getBodyFrameIterator(AMQProtocolSession protocolSession, int channel) - { - return new BodyFrameIterator(protocolSession, channel); - } - - public Iterator<ContentChunk> getContentBodyIterator() - { - return new BodyContentIterator(); - } - - public ContentHeaderBody getContentHeaderBody() throws AMQException - { - return _messageHandle.getContentHeaderBody(getStoreContext()); - } - - - - public Long getMessageId() - { - return _messageHandle.getMessageId(); - } - - /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic - * operation. - */ - public AMQMessage takeReference() - { - incrementReference(); // _referenceCount.incrementAndGet(); - - return this; - } - - public boolean incrementReference() - { - return incrementReference(1); - } - - /* Threadsafe. Increment the reference count on the message. */ - public boolean incrementReference(int count) - { - if(_referenceCount.addAndGet(count) <= 1) - { - _referenceCount.addAndGet(-count); - return false; - } - else - { - return true; - } - - } - - /** - * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the - * message store. - * - * @param storeContext - * - * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that - * failed - */ - public void decrementReference(StoreContext storeContext) throws MessageCleanupException - { - - int count = _referenceCount.decrementAndGet(); - - // note that the operation of decrementing the reference count and then removing the message does not - // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after - // the message has been passed to all queues. i.e. we are - // not relying on the all the increments having taken place before the delivery manager decrements. - if (count == 0) - { - // set the reference count way below 0 so that we can detect that the message has been deleted - // this is to guard against the message being spontaneously recreated (from the mgmt console) - // by copying from other queues at the same time as it is being removed. - _referenceCount.set(Integer.MIN_VALUE/2); - - try - { - // must check if the handle is null since there may be cases where we decide to throw away a message - // and the handle has not yet been constructed - if (_messageHandle != null) - { - _messageHandle.removeMessage(storeContext); - } - } - catch (AMQException e) - { - // to maintain consistency, we revert the count - incrementReference(); - throw new MessageCleanupException(getMessageId(), e); - } - } - else - { - if (count < 0) - { - throw new MessageCleanupException("Reference count for message id " + debugIdentity() - + " has gone below 0."); - } - } - } - - - /** - * Called selectors to determin if the message has already been sent - * - * @return _deliveredToConsumer - */ - public boolean getDeliveredToConsumer() - { - return (_flags & DELIVERED_TO_CONSUMER) != 0; - } - - public boolean isPersistent() throws AMQException - { - return _messageHandle.isPersistent(); - } - - /** - * Called to enforce the 'immediate' flag. - * - * @returns true if the message is marked for immediate delivery but has not been marked as delivered - * to a consumer - */ - public boolean immediateAndNotDelivered() - { - - return (_flags & IMMEDIATE_AND_DELIVERED) == IMMEDIATE; - - } - - public MessagePublishInfo getMessagePublishInfo() throws AMQException - { - return _messageHandle.getMessagePublishInfo(getStoreContext()); - } - - public boolean isRedelivered() - { - return _messageHandle.isRedelivered(); - } - - public void setRedelivered(boolean redelivered) - { - _messageHandle.setRedelivered(redelivered); - } - - public long getArrivalTime() - { - return _messageHandle.getArrivalTime(); - } - - /** - * Checks to see if the message has expired. If it has the message is dequeued. - * - * @param queue The queue to check the expiration against. (Currently not used) - * - * @return true if the message has expire - * - * @throws AMQException - */ - public boolean expired(AMQQueue queue) throws AMQException - { - - if (_expiration != 0L) - { - long now = System.currentTimeMillis(); - - return (now > _expiration); - } - - return false; - } - - /** - * Called when this message is delivered to a consumer. (used to implement the 'immediate' flag functionality). - * And for selector efficiency. - */ - public void setDeliveredToConsumer() - { - _flags |= DELIVERED_TO_CONSUMER; - } - - - - public AMQMessageHandle getMessageHandle() - { - return _messageHandle; - } - - public long getSize() - { - return _size; - - } - - public Object getPublisherClientInstance() - { - //todo store sessionIdentifier/client id with message in store - //Currently the _sessionIdentifier will be null if the message has been - // restored from a message Store - if (_sessionIdentifier == null) - { - return null; - } - else - { - return _sessionIdentifier.getSessionInstance(); - } - } - - public Object getPublisherIdentifier() - { - //todo store sessionIdentifier/client id with message in store - //Currently the _sessionIdentifier will be null if the message has been - // restored from a message Store - if (_sessionIdentifier == null) - { - return null; - } - else - { - return _sessionIdentifier.getSessionIdentifier(); - } - } - - public void setClientIdentifier(final AMQProtocolSession.ProtocolSessionIdentifier sessionIdentifier) - { - _sessionIdentifier = sessionIdentifier; - } - - - public String toString() - { - // return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + - // _taken + " by :" + _takenBySubcription; - - return "Message[" + debugIdentity() + "]: " + getMessageId() + "; ref count: " + _referenceCount; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java deleted file mode 100644 index 0ddd4e4d92..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessageHandle.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * A pluggable way of getting message data. Implementations can provide intelligent caching for example or - * even no caching at all to minimise the broker memory footprint. - */ -public interface AMQMessageHandle -{ - ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException; - - /** - * - * @return the messageId for the message associated with this handle - */ - Long getMessageId(); - - - /** - * @return the number of body frames associated with this message - */ - int getBodyCount(StoreContext context) throws AMQException; - - /** - * @return the size of the body - */ - long getBodySize(StoreContext context) throws AMQException; - - /** - * Get a particular content body - * @param index the index of the body to retrieve, must be between 0 and getBodyCount() - 1 - * @return a content body - * @throws IllegalArgumentException if the index is invalid - */ - ContentChunk getContentChunk(StoreContext context, int index) throws IllegalArgumentException, AMQException; - - void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) throws AMQException; - - MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException; - - boolean isRedelivered(); - - void setRedelivered(boolean redelivered); - - boolean isPersistent(); - - void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException; - - void removeMessage(StoreContext storeContext) throws AMQException; - - long getArrivalTime(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java index bb6ce65d42..51fbff76f4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQPriorityQueue.java @@ -24,7 +24,6 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.AMQException; public class AMQPriorityQueue extends SimpleAMQQueue { @@ -34,11 +33,19 @@ public class AMQPriorityQueue extends SimpleAMQQueue final boolean autoDelete, final VirtualHost virtualHost, int priorities) - throws AMQException { super(name, durable, owner, autoDelete, virtualHost, new PriorityQueueList.Factory(priorities)); } + public AMQPriorityQueue(String queueName, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, int priorities) + { + this(new AMQShortString(queueName), durable, new AMQShortString(owner),autoDelete,virtualHost,priorities); + } + public int getPriorities() { return ((PriorityQueueList) _entries).getPriorities(); @@ -52,16 +59,25 @@ public class AMQPriorityQueue extends SimpleAMQQueue while(subIter.advance() && !entry.isAcquired()) { final Subscription subscription = subIter.getNode().getSubscription(); - QueueEntry subnode = subscription.getLastSeenEntry(); - while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()) + if(!subscription.isClosed()) { - if(subscription.setLastSeenEntry(subnode,entry)) - { - break; - } - else + QueueContext context = (QueueContext) subscription.getQueueContext(); + if(context != null) { - subnode = subscription.getLastSeenEntry(); + QueueEntry subnode = context._lastSeenEntry; + QueueEntry released = context._releasedEntry; + while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired() && (released == null || released.compareTo(entry) < 0)) + { + if(QueueContext._releasedUpdater.compareAndSet(context,released,entry)) + { + break; + } + else + { + subnode = context._lastSeenEntry; + released = context._releasedEntry; + } + } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 184504717e..c9d20c53e4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -20,34 +20,49 @@ */ package org.apache.qpid.server.queue; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.Managable; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.exchange.ExchangeReferrer; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; import java.util.List; import java.util.Set; +import java.util.Map; -public interface AMQQueue extends Managable, Comparable<AMQQueue> +public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeReferrer, TransactionLogResource { + + public interface Context + { + QueueEntry getLastSeenEntry(); + } + AMQShortString getName(); + void setNoLocal(boolean b); + boolean isDurable(); boolean isAutoDelete(); AMQShortString getOwner(); + PrincipalHolder getPrincipalHolder(); + void setPrincipalHolder(PrincipalHolder principalHolder); + + void setExclusiveOwner(Object owner); + Object getExclusiveOwner(); VirtualHost getVirtualHost(); @@ -89,17 +104,19 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue> int delete() throws AMQException; - QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException; + QueueEntry enqueue(ServerMessage message) throws AMQException; + + void requeue(QueueEntry entry); - void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException; + void requeue(QueueEntryImpl storeContext, Subscription subscription); - void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException; + void dequeue(QueueEntry entry); boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; - + void addQueueDeleteTask(final Task task); @@ -113,11 +130,11 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue> List<Long> getMessagesOnTheQueue(int num, int offest); QueueEntry getMessageOnTheQueue(long messageId); - + /** * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. - * - * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. + * + * The 'queue position' index starts from 1. Using 0 in 'from' will be ignored and continue from 1. * Using 0 in the 'to' field will return an empty list regardless of the 'from' value. * @param fromPosition * @param toPosition @@ -127,11 +144,11 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue> void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, - StoreContext storeContext); + ServerTransaction transaction); - void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext); + void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction transaction); - void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext); + void removeMessagesFromQueue(long fromMessageId, long toMessageId); @@ -171,9 +188,9 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue> - void deleteMessageFromTop(StoreContext storeContext) throws AMQException; + void deleteMessageFromTop(); - long clearQueue(StoreContext storeContext) throws AMQException; + long clearQueue(); /** * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. @@ -191,6 +208,14 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue> void stop(); + boolean isExclusive(); + + Exchange getAlternateExchange(); + + void setAlternateExchange(Exchange exchange); + + Map<String, Object> getArguments(); + void checkCapacity(AMQChannel channel); /** @@ -242,6 +267,6 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue> } void configure(QueueConfiguration config); - + ManagedObject getManagedObject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 267ccf43ea..d4a5b3258b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -27,7 +27,6 @@ import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; -import java.util.HashMap; public class AMQQueueFactory @@ -130,7 +129,6 @@ public class AMQQueueFactory AMQShortString owner, boolean autoDelete, VirtualHost virtualHost, final FieldTable arguments) - throws AMQException { final int priorities = arguments == null ? 1 : arguments.containsKey(X_QPID_PRIORITIES) ? arguments.getInteger(X_QPID_PRIORITIES) : 1; @@ -189,4 +187,39 @@ public class AMQQueueFactory q.configure(config); return q; } + + public static AMQQueue createAMQQueueImpl(String queueName, + boolean durable, + String owner, + boolean autoDelete, + VirtualHost virtualHost, Map<String, Object> arguments) + throws AMQException + { + int priorities = 1; + if(arguments != null && arguments.containsKey(X_QPID_PRIORITIES)) + { + Object prioritiesObj = arguments.get(X_QPID_PRIORITIES); + if(prioritiesObj instanceof Number) + { + priorities = ((Number)prioritiesObj).intValue(); + } + } + + + AMQQueue q = null; + if(priorities > 1) + { + q = new AMQPriorityQueue(queueName, durable, owner, autoDelete, virtualHost, priorities); + } + else + { + q = new SimpleAMQQueue(queueName, durable, owner, autoDelete, virtualHost); + } + + //Register the new queue + virtualHost.getQueueRegistry().registerQueue(q); + q.configure(virtualHost.getConfiguration().getQueueConfiguration(queueName)); + return q; + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index d340c9a91f..8e5310bc16 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -22,23 +22,21 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; - import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.LocalTransaction; import javax.management.JMException; -import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.OperationsException; @@ -72,12 +70,6 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private static final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM-dd-yy HH:mm:ss.SSS z"); - /** - * Since the MBean is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - private StoreContext _storeContext = new StoreContext(); - private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method @@ -131,7 +123,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("Message Content", "AMQ Message Content", + _msgContentType = new CompositeType("Message Content", "AMQ Message Content", VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, VIEW_MSG_CONTENT_COMPOSITE_ITEM_DESCRIPTIONS, _msgContentAttributeTypes); @@ -141,9 +133,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered _msgAttributeTypes[4] = SimpleType.LONG; // For queue position - _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, + _messageDataType = new CompositeType("Message", "AMQ Message", VIEW_MSGS_COMPOSITE_ITEM_NAMES, VIEW_MSGS_COMPOSITE_ITEM_DESCRIPTIONS, _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, + _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, VIEW_MSGS_TABULAR_UNIQUE_INDEX); } @@ -164,7 +156,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public String getOwner() { - return String.valueOf(_queue.getOwner()); + return String.valueOf(_queue.getPrincipalHolder() == null + ? null + : _queue.getPrincipalHolder().getPrincipal() == null + ? null + : _queue.getPrincipalHolder().getPrincipal().getName()); } public boolean isAutoDelete() @@ -246,7 +242,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que /** * Checks if there is any notification to be send to the listeners */ - public void checkForNotification(AMQMessage msg) throws AMQException + public void checkForNotification(ServerMessage msg) throws AMQException { final Set<NotificationCheck> notificationChecks = _queue.getNotificationChecks(); @@ -296,32 +292,18 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ public void deleteMessageFromTop() throws JMException { - try - { - _queue.deleteMessageFromTop(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } + _queue.deleteMessageFromTop(); } /** * Clears the queue of non-acquired messages - * + * * @return the number of messages deleted * @see AMQQueue#clearQueue */ public Long clearQueue() throws JMException { - try - { - return _queue.clearQueue(_storeContext); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } + return _queue.clearQueue(); } /** @@ -336,49 +318,41 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); } - AMQMessage msg = entry.getMessage(); - // get message content - Iterator<ContentChunk> cBodies = msg.getContentBodyIterator(); + ServerMessage serverMsg = entry.getMessage(); + final int bodySize = (int) serverMsg.getSize(); + + List<Byte> msgContent = new ArrayList<Byte>(); - while (cBodies.hasNext()) - { - ContentChunk body = cBodies.next(); - if (body.getSize() != 0) - { - if (body.getSize() != 0) - { - ByteBuffer slice = body.getData().slice(); - for (int j = 0; j < slice.limit(); j++) - { - msgContent.add(slice.get()); - } - } - } - } - try + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(bodySize); + int position = 0; + + while(position < bodySize) { - // Create header attributes list - CommonContentHeaderProperties headerProperties = - (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; - String mimeType = null, encoding = null; - if (headerProperties != null) + position += serverMsg.getContent(buf, position); + buf.flip(); + for(int i = 0; i < buf.limit(); i++) { - AMQShortString mimeTypeShortSting = headerProperties.getContentType(); - mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); - encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); + msgContent.add(buf.get(i)); } + buf.clear(); + } - Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + AMQMessageHeader header = serverMsg.getMessageHeader(); - return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues); - } - catch (AMQException e) + String mimeType = null, encoding = null; + if (header != null) { - JMException jme = new JMException("Error creating header attributes list: " + e); - jme.initCause(e); - throw jme; + mimeType = header.getMimeType(); + + encoding = header.getEncoding(); } + + + Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + + return new CompositeDataSupport(_msgContentType, VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES, itemValues); + } /** @@ -390,8 +364,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { return viewMessages((long)beginIndex,(long)endIndex); } - - + + /** * Returns the header contents of the messages stored in this queue in tabular form. * @param startPosition The queue position of the first message to be viewed @@ -404,7 +378,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); } - + if ((endPosition - startPosition) > Integer.MAX_VALUE) { throw new OperationsException("Specified MessageID interval is too large. Intervals must be less than 2^31 in size"); @@ -421,13 +395,22 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que for (int i = 0; i < size ; i++) { long position = startPosition + i; - AMQMessage msg = list.get(i).getMessage(); - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered(), position}; - CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); - _messageList.put(messageData); + final QueueEntry queueEntry = list.get(i); + ServerMessage serverMsg = queueEntry.getMessage(); + if(serverMsg instanceof AMQMessage) + { + AMQMessage msg = (AMQMessage) serverMsg; + ContentHeaderBody headerBody = msg.getContentHeaderBody(); + // Create header attributes list + String[] headerAttributes = getMessageHeaderProperties(headerBody); + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, queueEntry.isRedelivered(), position}; + CompositeData messageData = new CompositeDataSupport(_messageDataType, VIEW_MSGS_COMPOSITE_ITEM_NAMES, itemValues); + _messageList.put(messageData); + } + else + { + // TODO 0-10 Message + } } } catch (AMQException e) @@ -484,7 +467,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog()); + _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn); + txn.commit(); } /** @@ -500,9 +485,9 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - _queue.removeMessagesFromQueue(fromMessageId, toMessageId, _storeContext); + _queue.removeMessagesFromQueue(fromMessageId, toMessageId); } - + /** * @see ManagedQueue#copyMessages * @param fromMessageId @@ -517,9 +502,15 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); + ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog()); + + _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn); + + txn.commit(); + + } - + /** * returns Notifications sent by this MBean. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index cbe9246f09..aea485e749 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -44,12 +44,12 @@ public class DefaultQueueRegistry implements QueueRegistry return _virtualHost; } - public void registerQueue(AMQQueue queue) throws AMQException + public void registerQueue(AMQQueue queue) { _queueMap.put(queue.getName(), queue); } - public void unregisterQueue(AMQShortString name) throws AMQException + public void unregisterQueue(AMQShortString name) { _queueMap.remove(name); } @@ -68,4 +68,9 @@ public class DefaultQueueRegistry implements QueueRegistry { return _queueMap.values(); } + + public AMQQueue getQueue(String queue) + { + return getQueue(new AMQShortString(queue)); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java index d38932bb61..eaa3992e98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/Filterable.java @@ -22,12 +22,13 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.AMQMessageHeader; -public interface Filterable<E extends Exception> +public interface Filterable { - ContentHeaderBody getContentHeaderBody() throws E; + AMQMessageHeader getMessageHeader(); - boolean isPersistent() throws E; + boolean isPersistent(); boolean isRedelivered(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java deleted file mode 100644 index 35ad5be4e0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InMemoryMessageHandle.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.util.Collections; -import java.util.ArrayList; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.StoreContext; - -/** - */ -public class InMemoryMessageHandle implements AMQMessageHandle -{ - - private ContentHeaderBody _contentHeaderBody; - - private MessagePublishInfo _messagePublishInfo; - - private List<ContentChunk> _contentBodies; - - private boolean _redelivered; - - private long _arrivalTime; - - private final Long _messageId; - - public InMemoryMessageHandle(final Long messageId) - { - _messageId = messageId; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException - { - return _contentHeaderBody; - } - - public Long getMessageId() - { - return _messageId; - } - - public int getBodyCount(StoreContext context) - { - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context) throws AMQException - { - return getContentHeaderBody(context).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException - { - if (index > _contentBodies.size() - 1) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - return _contentBodies.get(index); - } - - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentBody, boolean isLastContentBody) - throws AMQException - { - if(_contentBodies == null) - { - if(isLastContentBody) - { - _contentBodies = Collections.singletonList(contentBody); - } - else - { - _contentBodies = new ArrayList<ContentChunk>(); - _contentBodies.add(contentBody); - } - } - else - { - _contentBodies.add(contentBody); - } - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException - { - return _messagePublishInfo; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent() - { - return false; - } - - /** - * This is called when all the content has been received. - * @param messagePublishInfo - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo messagePublishInfo, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - _messagePublishInfo = messagePublishInfo; - _contentHeaderBody = contentHeaderBody; - if(contentHeaderBody.bodySize == 0) - { - _contentBodies = Collections.EMPTY_LIST; - } - _arrivalTime = System.currentTimeMillis(); - } - - public void removeMessage(StoreContext storeContext) throws AMQException - { - // NO OP - } - - public long getArrivalTime() - { - return _arrivalTime; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java index d6fd1eec89..77da08d8c4 100644..100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NoConsumersException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java @@ -18,30 +18,54 @@ * under the License. * */ + package org.apache.qpid.server.queue; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.AMQMessageHeader; -/** - * NoConsumersException is a {@link RequiredDeliveryException} that represents the failure case where an immediate - * message cannot be delivered because there are presently no consumers for the message. The AMQP status code, 313, is - * always used to report this condition. - * - * <p/><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities <th> Collaborations - * <tr><td> Represent failure to deliver a message that must be delivered. - * </table> - */ -public class NoConsumersException extends RequiredDeliveryException +class InboundMessageAdapter implements InboundMessage { - public NoConsumersException(AMQMessage message) + + private QueueEntry _entry; + + InboundMessageAdapter() + { + } + + InboundMessageAdapter(QueueEntry entry) + { + _entry = entry; + } + + public void setEntry(QueueEntry entry) + { + _entry = entry; + } + + + public String getRoutingKey() + { + return _entry.getMessage().getRoutingKey(); + } + + public AMQMessageHeader getMessageHeader() + { + return _entry.getMessageHeader(); + } + + public boolean isPersistent() + { + return _entry.isPersistent(); + } + + public boolean isRedelivered() { - super("Immediate delivery is not possible.", message); + return _entry.isRedelivered(); } - public AMQConstant getReplyCode() + public long getSize() { - return AMQConstant.NO_CONSUMERS; + return _entry.getSize(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java index d5e0b4d187..da4173d5d3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -25,19 +25,22 @@ import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.exchange.NoRouteException; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.MessageContentSource; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; +import java.nio.ByteBuffer; -public class IncomingMessage implements Filterable<RuntimeException> +public class IncomingMessage implements Filterable, InboundMessage, EnqueableMessage, MessageContentSource { /** Used for debugging purposes. */ @@ -48,12 +51,6 @@ public class IncomingMessage implements Filterable<RuntimeException> private final MessagePublishInfo _messagePublishInfo; private ContentHeaderBody _contentHeaderBody; - private AMQMessageHandle _messageHandle; - private final Long _messageId; - private final TransactionalContext _txnContext; - - private static final boolean MSG_AUTH = - ApplicationRegistry.getInstance().getConfiguration().getMsgAuth(); /** @@ -68,23 +65,27 @@ public class IncomingMessage implements Filterable<RuntimeException> */ private ArrayList<AMQQueue> _destinationQueues; - private AMQProtocolSession _publisher; - private MessageStore _messageStore; private long _expiration; - + private Exchange _exchange; - public IncomingMessage(final Long messageId, - final MessagePublishInfo info, - final TransactionalContext txnContext, - final AMQProtocolSession publisher) + private int _receivedChunkCount = 0; + private List<ContentChunk> _contentChunks = new ArrayList<ContentChunk>(); + + // we keep both the original meta data object and the store reference to it just in case the + // store would otherwise flow it to disk + + private MessageMetaData _messageMetaData; + + private StoredMessage<MessageMetaData> _storedMessageHandle; + + + public IncomingMessage( + final MessagePublishInfo info + ) { - _messageId = messageId; _messagePublishInfo = info; - _txnContext = txnContext; - _publisher = publisher; - } public void setContentHeaderBody(final ContentHeaderBody contentHeaderBody) throws AMQException @@ -123,183 +124,94 @@ public class IncomingMessage implements Filterable<RuntimeException> } - public void routingComplete(final MessageStore store, - final MessageHandleFactory factory) throws AMQException + public MessageMetaData headersReceived() { - - final boolean persistent = isPersistent(); - _messageHandle = factory.createMessageHandle(_messageId, store, persistent); - if (persistent) - { - _txnContext.beginTranIfNecessary(); - // enqueuing the messages ensure that if required the destinations are recorded to a - // persistent store - - if(_destinationQueues != null) - { - for (int i = 0; i < _destinationQueues.size(); i++) - { - store.enqueueMessage(_txnContext.getStoreContext(), - _destinationQueues.get(i), _messageId); - } - } - } + _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0); + return _messageMetaData; } - public AMQMessage deliverToQueues() - throws AMQException - { - - // we get a reference to the destination queues now so that we can clear the - // transient message data as quickly as possible - if (_logger.isDebugEnabled()) - { - _logger.debug("Delivering message " + _messageId + " to " + _destinationQueues); - } - - AMQMessage message = null; - - try - { - // first we allow the handle to know that the message has been fully received. This is useful if it is - // maintaining any calculated values based on content chunks - _messageHandle.setPublishAndContentHeaderBody(_txnContext.getStoreContext(), - _messagePublishInfo, getContentHeaderBody()); - - - - message = new AMQMessage(_messageHandle,_txnContext.getStoreContext(), _messagePublishInfo); - - message.setExpiration(_expiration); - message.setClientIdentifier(_publisher.getSessionIdentifier()); - - // we then allow the transactional context to do something with the message content - // now that it has all been received, before we attempt delivery - _txnContext.messageFullyReceived(isPersistent()); - - AMQShortString userID = getContentHeaderBody().properties instanceof BasicContentHeaderProperties ? - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getUserId() : null; - - if (MSG_AUTH && !_publisher.getAuthorizedID().getName().equals(userID == null? "" : userID.toString())) - { - throw new UnauthorizedAccessException("Acccess Refused",message); - } - - if ((_destinationQueues == null) || _destinationQueues.size() == 0) - { - - if (isMandatory() || isImmediate()) - { - throw new NoRouteException("No Route for message", message); - - } - else - { - _logger.warn("MESSAGE DISCARDED: No routes for message - " + message); - } - } - else - { - int offset; - final int queueCount = _destinationQueues.size(); - message.incrementReference(queueCount); - if(queueCount == 1) - { - offset = 0; - } - else - { - offset = ((int)(message.getMessageId().longValue())) % queueCount; - if(offset < 0) - { - offset = -offset; - } - } - for (int i = offset; i < queueCount; i++) - { - // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), message); - } - for (int i = 0; i < offset; i++) - { - // normal deliver so add this message at the end. - _txnContext.deliver(_destinationQueues.get(i), message); - } - } - - message.clearStoreContext(); - return message; - } - finally - { - // Remove refence for routing process . Reference count should now == delivered queue count - if(message != null) message.decrementReference(_txnContext.getStoreContext()); - } + public ArrayList<AMQQueue> getDestinationQueues() + { + return _destinationQueues; } - public void addContentBodyFrame(final ContentChunk contentChunk) + public int addContentBodyFrame(final ContentChunk contentChunk) throws AMQException { - + _storedMessageHandle.addContent((int)_bodyLengthReceived, contentChunk.getData().buf()); _bodyLengthReceived += contentChunk.getSize(); + _contentChunks.add(contentChunk); + - _messageHandle.addContentBodyFrame(_txnContext.getStoreContext(), contentChunk, allContentReceived()); + return _receivedChunkCount++; } public boolean allContentReceived() { - return (_bodyLengthReceived == getContentHeaderBody().bodySize); + return (_bodyLengthReceived == getContentHeader().bodySize); } - public AMQShortString getExchange() throws AMQException + public AMQShortString getExchange() { return _messagePublishInfo.getExchange(); } - public AMQShortString getRoutingKey() throws AMQException + public String getRoutingKey() { - return _messagePublishInfo.getRoutingKey(); + return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString(); } - public boolean isMandatory() throws AMQException + public String getBinding() + { + return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString(); + } + + + public boolean isMandatory() { return _messagePublishInfo.isMandatory(); } - public boolean isImmediate() throws AMQException + public boolean isImmediate() { return _messagePublishInfo.isImmediate(); } - public ContentHeaderBody getContentHeaderBody() + public ContentHeaderBody getContentHeader() { return _contentHeaderBody; } + public AMQMessageHeader getMessageHeader() + { + return _messageMetaData.getMessageHeader(); + } + public boolean isPersistent() { - return getContentHeaderBody().properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) getContentHeaderBody().properties).getDeliveryMode() == + return getContentHeader().properties instanceof BasicContentHeaderProperties && + ((BasicContentHeaderProperties) getContentHeader().properties).getDeliveryMode() == BasicContentHeaderProperties.PERSISTENT; } - + public boolean isRedelivered() { return false; } - public void setMessageStore(final MessageStore messageStore) + + public long getSize() { - _messageStore = messageStore; + return getContentHeader().bodySize; } - public Long getMessageId() + public Long getMessageNumber() { - return _messageId; + return _storedMessageHandle.getMessageNumber(); } public void setExchange(final Exchange e) @@ -307,13 +219,82 @@ public class IncomingMessage implements Filterable<RuntimeException> _exchange = e; } - public void route() throws AMQException + public void route() { - _exchange.route(this); + enqueue(_exchange.route(this)); + } public void enqueue(final ArrayList<AMQQueue> queues) { _destinationQueues = queues; } + + public MessagePublishInfo getMessagePublishInfo() + { + return _messagePublishInfo; + } + + public long getExpiration() + { + return _expiration; + } + + public int getReceivedChunkCount() + { + return _receivedChunkCount; + } + + + public int getBodyCount() throws AMQException + { + return _contentChunks.size(); + } + + public ContentChunk getContentChunk(int index) throws IllegalArgumentException, AMQException + { + return _contentChunks.get(index); + } + + + public int getContent(ByteBuffer buf, int offset) + { + int pos = 0; + int written = 0; + for(ContentChunk cb : _contentChunks) + { + ByteBuffer data = cb.getData().buf(); + if(offset+written >= pos && offset < pos + data.limit()) + { + ByteBuffer src = data.duplicate(); + src.position(offset+written - pos); + src = src.slice(); + + if(buf.remaining() < src.limit()) + { + src.limit(buf.remaining()); + } + int count = src.limit(); + buf.put(src); + written += count; + if(buf.remaining() == 0) + { + break; + } + } + pos+=data.limit(); + } + return written; + + } + + public void setStoredMessage(StoredMessage<MessageMetaData> storedMessageHandle) + { + _storedMessageHandle = storedMessageHandle; + } + + public StoredMessage<MessageMetaData> getStoredMessage() + { + return _storedMessageHandle; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java deleted file mode 100644 index 6118a4c11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/MessageMetaData.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; - -/** - * Encapsulates a publish body and a content header. In the context of the message store these are treated as a - * single unit. - */ -public class MessageMetaData -{ - private MessagePublishInfo _messagePublishInfo; - - private ContentHeaderBody _contentHeaderBody; - - private int _contentChunkCount; - - private long _arrivalTime; - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount) - { - this(publishBody,contentHeaderBody, contentChunkCount, System.currentTimeMillis()); - } - - public MessageMetaData(MessagePublishInfo publishBody, ContentHeaderBody contentHeaderBody, int contentChunkCount, long arrivalTime) - { - _contentHeaderBody = contentHeaderBody; - _messagePublishInfo = publishBody; - _contentChunkCount = contentChunkCount; - _arrivalTime = arrivalTime; - } - - public int getContentChunkCount() - { - return _contentChunkCount; - } - - public void setContentChunkCount(int contentChunkCount) - { - _contentChunkCount = contentChunkCount; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public long getArrivalTime() - { - return _arrivalTime; - } - - public void setArrivalTime(long arrivalTime) - { - _arrivalTime = arrivalTime; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index 6f9efd3200..d1fb0f3fe6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -21,13 +21,14 @@ package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
+import org.apache.qpid.server.message.ServerMessage;
public enum NotificationCheck
{
MESSAGE_COUNT_ALERT
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
int msgCount;
final long maximumMessageCount = queue.getMaximumMessageCount();
@@ -41,26 +42,19 @@ public enum NotificationCheck },
MESSAGE_SIZE_ALERT(true)
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
final long maximumMessageSize = queue.getMaximumMessageSize();
if(maximumMessageSize != 0)
{
// Check for threshold message size
long messageSize;
- try
- {
- messageSize = (msg == null) ? 0 : msg.getContentHeaderBody().bodySize;
- }
- catch (AMQException e)
- {
- messageSize = 0;
- }
+ messageSize = (msg == null) ? 0 : msg.getSize();
if (messageSize >= maximumMessageSize)
{
- listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageId() + "]");
+ listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageNumber() + "]");
return true;
}
}
@@ -70,7 +64,7 @@ public enum NotificationCheck },
QUEUE_DEPTH_ALERT
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
// Check for threshold queue depth in bytes
final long maximumQueueDepth = queue.getMaximumQueueDepth();
@@ -91,7 +85,7 @@ public enum NotificationCheck },
MESSAGE_AGE_ALERT
{
- boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
{
final long maxMessageAge = queue.getMaximumMessageAge();
@@ -133,6 +127,6 @@ public enum NotificationCheck return _messageSpecific;
}
- abstract boolean notifyIfNecessary(AMQMessage msg, AMQQueue queue, QueueNotificationListener listener);
+ abstract boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java index fd46a8a5ff..0c6b84d2b6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/PriorityQueueList.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.CommonContentHeaderProperties; import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.ServerMessage; public class PriorityQueueList implements QueueEntryList { @@ -52,26 +53,18 @@ public class PriorityQueueList implements QueueEntryList return _queue; } - public QueueEntry add(AMQMessage message) + public QueueEntry add(ServerMessage message) { - try + int index = message.getMessageHeader().getPriority() - _priorityOffset; + if(index >= _priorities) { - int index = ((CommonContentHeaderProperties)((message.getContentHeaderBody().properties))).getPriority() - _priorityOffset; - if(index >= _priorities) - { - index = _priorities-1; - } - else if(index < 0) - { - index = 0; - } - return _priorityLists[index].add(message); + index = _priorities-1; } - catch (AMQException e) + else if(index < 0) { - // TODO - fix AMQ Exception - throw new RuntimeException(e); + index = 0; } + return _priorityLists[index].add(message); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java index 295cb266b9..825a85a89c 100644..100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/UnauthorizedAccessException.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueContext.java @@ -21,25 +21,29 @@ package org.apache.qpid.server.queue; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.RequiredDeliveryException; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -/** - * UnauthorizedAccessException is a {@link RequiredDeliveryException} that represents the failure case where a message - * is published with a user id different from the one used when creating the connection . - * The AMQP status code, 403, is always used to report this condition. - * - */ - -public class UnauthorizedAccessException extends RequiredDeliveryException +final class QueueContext implements AMQQueue.Context { - public UnauthorizedAccessException(String msg, AMQMessage amqMessage) + volatile QueueEntry _lastSeenEntry; + volatile QueueEntry _releasedEntry; + + static final AtomicReferenceFieldUpdater<QueueContext, QueueEntry> + _lastSeenUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueContext.class, QueueEntry.class, "_lastSeenEntry"); + static final AtomicReferenceFieldUpdater<QueueContext, QueueEntry> + _releasedUpdater = + AtomicReferenceFieldUpdater.newUpdater + (QueueContext.class, QueueEntry.class, "_releasedEntry"); + + public QueueContext(QueueEntry head) { - super(msg, amqMessage); + _lastSeenEntry = head; } - public AMQConstant getReplyCode() + public QueueEntry getLastSeenEntry() { - return AMQConstant.ACCESS_REFUSED; + return _lastSeenEntry; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java index 2657c459a9..a50e2b561d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java @@ -1,8 +1,8 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.message.ServerMessage; /* * @@ -24,18 +24,19 @@ import org.apache.qpid.server.subscription.Subscription; * under the License. * */ -public interface QueueEntry extends Comparable<QueueEntry> +public interface QueueEntry extends Comparable<QueueEntry>, Filterable { - public static enum State { AVAILABLE, ACQUIRED, EXPIRED, DEQUEUED, - DELETED + DELETED; + + } public static interface StateChangeListener @@ -121,6 +122,27 @@ public interface QueueEntry extends Comparable<QueueEntry> } } + public final class SubscriptionAssignedState extends EntryState + { + private final Subscription _subscription; + + public SubscriptionAssignedState(Subscription subscription) + { + _subscription = subscription; + } + + + public State getState() + { + return State.AVAILABLE; + } + + public Subscription getSubscription() + { + return _subscription; + } + } + final static EntryState AVAILABLE_STATE = new AvailableState(); final static EntryState DELETED_STATE = new DeletedState(); @@ -133,7 +155,7 @@ public interface QueueEntry extends Comparable<QueueEntry> AMQQueue getQueue(); - AMQMessage getMessage(); + ServerMessage getMessage(); long getSize(); @@ -150,16 +172,17 @@ public interface QueueEntry extends Comparable<QueueEntry> boolean isDeleted(); boolean acquiredBySubscription(); - - void setDeliveredToSubscription(); + boolean isAcquiredBy(Subscription subscription); void release(); + boolean releaseButRetain(); - String debugIdentity(); boolean immediateAndNotDelivered(); - void setRedelivered(boolean b); + void setRedelivered(); + + boolean isRedelivered(); Subscription getDeliveredSubscription(); @@ -169,13 +192,15 @@ public interface QueueEntry extends Comparable<QueueEntry> boolean isRejectedBy(Subscription subscription); - void requeue(StoreContext storeContext) throws AMQException; + void requeue(Subscription subscription); + + void dequeue(); - void dequeue(final StoreContext storeContext) throws FailedDequeueException; + void dispose(); - void dispose(final StoreContext storeContext) throws MessageCleanupException; + void discard(); - void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException; + void routeToAlternate(); boolean isQueueDeleted(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 3b58f05f93..5873e8f566 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -21,12 +21,16 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; import org.apache.log4j.Logger; -import java.util.Set; -import java.util.HashSet; +import java.util.*; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.concurrent.CopyOnWriteArraySet; @@ -42,7 +46,7 @@ public class QueueEntryImpl implements QueueEntry private final SimpleQueueEntryList _queueEntryList; - private final AMQMessage _message; + private MessageReference _message; private Set<Subscription> _rejectedBy = null; @@ -75,6 +79,11 @@ public class QueueEntryImpl implements QueueEntry volatile QueueEntryImpl _next; + private static final int DELIVERED_TO_CONSUMER = 1; + private static final int REDELIVERED = 2; + + private volatile int _deliveryState; + QueueEntryImpl(SimpleQueueEntryList queueEntryList) { @@ -83,18 +92,19 @@ public class QueueEntryImpl implements QueueEntry } - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message, final long entryId) + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message, final long entryId) { _queueEntryList = queueEntryList; - _message = message; + + _message = message == null ? null : message.newReference(); _entryIdUpdater.set(this, entryId); } - public QueueEntryImpl(SimpleQueueEntryList queueEntryList, AMQMessage message) + public QueueEntryImpl(SimpleQueueEntryList queueEntryList, ServerMessage message) { _queueEntryList = queueEntryList; - _message = message; + _message = message == null ? null : message.newReference(); } protected void setEntryId(long entryId) @@ -112,24 +122,36 @@ public class QueueEntryImpl implements QueueEntry return _queueEntryList.getQueue(); } - public AMQMessage getMessage() + public ServerMessage getMessage() { - return _message; + return _message == null ? null : _message.getMessage(); } public long getSize() { - return getMessage().getSize(); + return getMessage() == null ? 0 : getMessage().getSize(); } public boolean getDeliveredToConsumer() { - return getMessage().getDeliveredToConsumer(); + return (_deliveryState & DELIVERED_TO_CONSUMER) != 0; } public boolean expired() throws AMQException { - return getMessage().expired(getQueue()); + ServerMessage message = getMessage(); + if(message != null) + { + long expiration = message.getExpiration(); + if (expiration != 0L) + { + long now = System.currentTimeMillis(); + + return (now > expiration); + } + } + return false; + } public boolean isAcquired() @@ -145,6 +167,24 @@ public class QueueEntryImpl implements QueueEntry private boolean acquire(final EntryState state) { boolean acquired = _stateUpdater.compareAndSet(this,AVAILABLE_STATE, state); + + // deal with the case where the node has been assigned to a given subscription already + // including the case that the node is assigned to a closed subscription + if(!acquired) + { + if(state != NON_SUBSCRIPTION_ACQUIRED_STATE) + { + EntryState currentState = _state; + if(currentState.getState() == State.AVAILABLE + && ((currentState == AVAILABLE_STATE) + || (((SubscriptionAcquiredState)state).getSubscription() == + ((SubscriptionAssignedState)currentState).getSubscription()) + || ((SubscriptionAssignedState)currentState).getSubscription().isClosed() )) + { + acquired = _stateUpdater.compareAndSet(this,currentState, state); + } + } + } if(acquired && _stateChangeListeners != null) { notifyStateChange(State.AVAILABLE, State.ACQUIRED); @@ -155,7 +195,12 @@ public class QueueEntryImpl implements QueueEntry public boolean acquire(Subscription sub) { - return acquire(sub.getOwningState()); + final boolean acquired = acquire(sub.getOwningState()); + if(acquired) + { + _deliveryState |= DELIVERED_TO_CONSUMER; + } + return acquired; } public boolean acquiredBySubscription() @@ -164,38 +209,89 @@ public class QueueEntryImpl implements QueueEntry return (_state instanceof SubscriptionAcquiredState); } - public void setDeliveredToSubscription() + public boolean isAcquiredBy(Subscription subscription) { - getMessage().setDeliveredToConsumer(); + EntryState state = _state; + return state instanceof SubscriptionAcquiredState + && ((SubscriptionAcquiredState)state).getSubscription() == subscription; } public void release() { _stateUpdater.set(this,AVAILABLE_STATE); - } + if(!getQueue().isDeleted()) + { + getQueue().requeue(this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } - public String debugIdentity() - { - AMQMessage message = getMessage(); - if (message == null) + } + else if(acquire()) { - return "null"; + routeToAlternate(); } - else + + + } + + public boolean releaseButRetain() + { + EntryState state = _state; + + boolean stateUpdated = false; + + if(state instanceof SubscriptionAcquiredState) { - return message.debugIdentity(); + Subscription sub = ((SubscriptionAcquiredState) state).getSubscription(); + if(_stateUpdater.compareAndSet(this, state, sub.getAssignedState())) + { + System.err.println("Message released (and retained)" + getMessage().getMessageNumber()); + getQueue().requeue(this); + if(_stateChangeListeners != null) + { + notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); + } + stateUpdated = true; + } } + + return stateUpdated; + } + public boolean immediateAndNotDelivered() + { + return !getDeliveredToConsumer() && isImmediate(); + } + + private boolean isImmediate() + { + final ServerMessage message = getMessage(); + return message != null && message.isImmediate(); + } - public boolean immediateAndNotDelivered() + public void setRedelivered() { - return getMessage().immediateAndNotDelivered(); + _deliveryState |= REDELIVERED; } - public void setRedelivered(boolean b) + public AMQMessageHeader getMessageHeader() { - getMessage().setRedelivered(b); + final ServerMessage message = getMessage(); + return message == null ? null : message.getMessageHeader(); + } + + public boolean isPersistent() + { + final ServerMessage message = getMessage(); + return message != null && message.isPersistent(); + } + + public boolean isRedelivered() + { + return (_deliveryState & REDELIVERED) != 0; } public Subscription getDeliveredSubscription() @@ -230,12 +326,12 @@ public class QueueEntryImpl implements QueueEntry } else { - _log.warn("Requesting rejection by null subscriber:" + debugIdentity()); + _log.warn("Requesting rejection by null subscriber:" + this); } } public boolean isRejectedBy(Subscription subscription) - { + { if (_rejectedBy != null) // We have subscriptions that rejected this message { @@ -247,17 +343,16 @@ public class QueueEntryImpl implements QueueEntry } } - - public void requeue(final StoreContext storeContext) throws AMQException + public void requeue(Subscription subscription) { - getQueue().requeue(storeContext, this); + getQueue().requeue(this, subscription); if(_stateChangeListeners != null) { notifyStateChange(QueueEntry.State.ACQUIRED, QueueEntry.State.AVAILABLE); } } - public void dequeue(final StoreContext storeContext) throws FailedDequeueException + public void dequeue() { EntryState state = _state; @@ -266,10 +361,10 @@ public class QueueEntryImpl implements QueueEntry if (state instanceof SubscriptionAcquiredState) { Subscription s = ((SubscriptionAcquiredState) state).getSubscription(); - s.restoreCredit(this); + s.onDequeue(this); } - getQueue().dequeue(storeContext, this); + getQueue().dequeue(this); if(_stateChangeListeners != null) { notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); @@ -287,23 +382,74 @@ public class QueueEntryImpl implements QueueEntry } } - public void dispose(final StoreContext storeContext) throws MessageCleanupException + public void dispose() { if(delete()) { - getMessage().decrementReference(storeContext); + _message.release(); } } - public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException + public void discard() { //if the queue is null then the message is waiting to be acked, but has been removed. if (getQueue() != null) { - dequeue(storeContext); + dequeue(); } - dispose(storeContext); + dispose(); + } + + public void routeToAlternate() + { + final AMQQueue currentQueue = getQueue(); + Exchange alternateExchange = currentQueue.getAlternateExchange(); + + if(alternateExchange != null) + { + final List<AMQQueue> rerouteQueues = alternateExchange.route(new InboundMessageAdapter(this)); + final ServerMessage message = getMessage(); + if(rerouteQueues != null && rerouteQueues.size() != 0) + { + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + + txn.enqueue(rerouteQueues, message, new ServerTransaction.Action() { + public void postCommit() + { + try + { + for(AMQQueue queue : rerouteQueues) + { + QueueEntry entry = queue.enqueue(message); + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + + public void onRollback() + { + + } + }); + txn.dequeue(currentQueue,message, + new ServerTransaction.Action() + { + public void postCommit() + { + discard(); + } + + public void onRollback() + { + + } + }); + } + } } public boolean isQueueDeleted() @@ -379,7 +525,7 @@ public class QueueEntryImpl implements QueueEntry if(state != DELETED_STATE && _stateUpdater.compareAndSet(this,state,DELETED_STATE)) { - _queueEntryList.advanceHead(); + _queueEntryList.advanceHead(); return true; } else diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java index 313e076f61..b4042ce02c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java @@ -20,11 +20,13 @@ */ package org.apache.qpid.server.queue; +import org.apache.qpid.server.message.ServerMessage; + public interface QueueEntryList { AMQQueue getQueue(); - QueueEntry add(AMQMessage message); + QueueEntry add(ServerMessage message); QueueEntry next(QueueEntry node); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index 1210f0e97c..a537e0c83f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -30,9 +30,9 @@ public interface QueueRegistry { VirtualHost getVirtualHost(); - void registerQueue(AMQQueue queue) throws AMQException; + void registerQueue(AMQQueue queue); - void unregisterQueue(AMQShortString name) throws AMQException; + void unregisterQueue(AMQShortString name); AMQQueue getQueue(AMQShortString name); @@ -40,4 +40,5 @@ public interface QueueRegistry Collection<AMQQueue> getQueues(); + AMQQueue getQueue(String queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index d781dc4dea..77a6fb9328 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -3,12 +3,9 @@ package org.apache.qpid.server.queue; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import javax.management.JMException; @@ -21,13 +18,12 @@ import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.QueueActor; import org.apache.qpid.server.logging.subjects.QueueLogSubject; @@ -35,6 +31,9 @@ import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.messages.QueueMessages; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; /* * @@ -60,24 +59,40 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + + private final VirtualHost _virtualHost; + private final AMQShortString _name; + private final String _resourceName; /** null means shared */ private final AMQShortString _owner; + private PrincipalHolder _prinicpalHolder; + + private Object _exclusiveOwner; + + private final boolean _durable; /** If true, this queue is deleted when the last subscriber is removed */ private final boolean _autoDelete; - private final VirtualHost _virtualHost; + private Exchange _alternateExchange; /** Used to track bindings to exchanges so that on deletion they can easily be cancelled. */ private final ExchangeBindings _bindings = new ExchangeBindings(this); - private final AtomicBoolean _deleted = new AtomicBoolean(false); - private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>(); + protected final QueueEntryList _entries; + + protected final SubscriptionList _subscriptionList = new SubscriptionList(this); + + private final AtomicReference<SubscriptionList.SubscriptionNode> _lastSubscriptionNode = new AtomicReference<SubscriptionList.SubscriptionNode>(_subscriptionList.getHead()); + + private volatile Subscription _exclusiveSubscriber; + + private final AtomicInteger _atomicQueueCount = new AtomicInteger(0); @@ -85,18 +100,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final AtomicInteger _activeSubscriberCount = new AtomicInteger(); - protected final SubscriptionList _subscriptionList = new SubscriptionList(this); - private final AtomicReference<SubscriptionList.SubscriptionNode> _lastSubscriptionNode = new AtomicReference<SubscriptionList.SubscriptionNode>(_subscriptionList.getHead()); - - private volatile Subscription _exclusiveSubscriber; + private final AtomicLong _totalMessagesReceived = new AtomicLong(); - protected final QueueEntryList _entries; - private final AMQQueueMBean _managedObject; - private final Executor _asyncDelivery; - private final AtomicLong _totalMessagesReceived = new AtomicLong(); - private final ConcurrentMap<AMQChannel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQChannel, Boolean>(); /** max allowed size(KB) of a single message */ public long _maximumMessageSize = ApplicationRegistry.getInstance().getConfiguration().getMaximumMessageSize(); @@ -113,24 +120,38 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener /** the minimum interval between sending out consecutive alerts of the same type */ public long _minimumAlertRepeatGap = ApplicationRegistry.getInstance().getConfiguration().getMinimumAlertRepeatGap(); - private static final int MAX_ASYNC_DELIVERIES = 10; + private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity(); + + private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity(); private final Set<NotificationCheck> _notificationChecks = EnumSet.noneOf(NotificationCheck.class); + + static final int MAX_ASYNC_DELIVERIES = 10; + + private final AtomicLong _stateChangeCount = new AtomicLong(Long.MIN_VALUE); private AtomicReference _asynchronousRunner = new AtomicReference(null); + private final Executor _asyncDelivery; private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); + + private final ConcurrentMap<AMQChannel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQChannel, Boolean>(); + + private final AtomicBoolean _deleted = new AtomicBoolean(false); + private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>(); + + private LogSubject _logSubject; private LogActor _logActor; + private AMQQueueMBean _managedObject; + private static final String SUB_FLUSH_RUNNER = "SUB_FLUSH_RUNNER"; + private boolean _nolocal; - private long _capacity = ApplicationRegistry.getInstance().getConfiguration().getCapacity(); - private long _flowResumeCapacity = ApplicationRegistry.getInstance().getConfiguration().getFlowResumeCapacity(); private final AtomicBoolean _overfull = new AtomicBoolean(false); protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, VirtualHost virtualHost) - throws AMQException { this(name, durable, owner, autoDelete, virtualHost, new SimpleQueueEntryList.Factory()); } @@ -141,7 +162,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener boolean autoDelete, VirtualHost virtualHost, QueueEntryListFactory entryListFactory) - throws AMQException { if (name == null) @@ -155,6 +175,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } _name = name; + _resourceName = String.valueOf(name); _durable = durable; _owner = owner; _autoDelete = autoDelete; @@ -193,13 +214,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } catch (JMException e) { - throw new AMQException("AMQQueue MBean creation has failed ", e); + _logger.error("AMQQueue MBean creation has failed ", e); } resetNotifications(); } + public SimpleAMQQueue(String queueName, boolean durable, String owner, boolean autoDelete, VirtualHost virtualHost) + throws AMQException + { + this(new AMQShortString(queueName), durable, owner == null ? null : new AMQShortString(owner),autoDelete,virtualHost); + } + public void resetNotifications() { // This ensure that the notification checks for the configured alerts are created. @@ -211,16 +238,54 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Getters and Setters + public void execute(ReadWriteRunnable runnable) + { + _asyncDelivery.execute(runnable); + } + public AMQShortString getName() { return _name; } + public void setNoLocal(boolean nolocal) + { + _nolocal = nolocal; + } + public boolean isDurable() { return _durable; } + public boolean isExclusive() + { + return _exclusiveOwner != null; + } + + public Exchange getAlternateExchange() + { + return _alternateExchange; + } + + public void setAlternateExchange(Exchange exchange) + { + if(_alternateExchange != null) + { + _alternateExchange.removeReference(this); + } + if(exchange != null) + { + exchange.addReference(this); + } + _alternateExchange = exchange; + } + + public Map<String, Object> getArguments() + { + return null; + } + public boolean isAutoDelete() { return _autoDelete; @@ -231,6 +296,17 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return _owner; } + public PrincipalHolder getPrincipalHolder() + { + return _prinicpalHolder; + } + + public void setPrincipalHolder(PrincipalHolder prinicpalHolder) + { + _prinicpalHolder = prinicpalHolder; + } + + public VirtualHost getVirtualHost() { return _virtualHost; @@ -238,13 +314,31 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ bind and unbind + public void bind(Exchange exchange, String bindingKey, Map<String, Object> arguments) throws AMQException + { + + FieldTable fieldTable = FieldTable.convertToFieldTable(arguments); + AMQShortString routingKey = new AMQShortString(bindingKey); + + exchange.registerQueue(routingKey, this, fieldTable); + + if (isDurable() && exchange.isDurable()) + { + + _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, fieldTable); + } + + _bindings.addBinding(routingKey, fieldTable, exchange); + } + + public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException { exchange.registerQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().bindQueue(exchange, routingKey, this, arguments); + _virtualHost.getDurableConfigurationStore().bindQueue(exchange, routingKey, this, arguments); } _bindings.addBinding(routingKey, arguments, exchange); @@ -255,7 +349,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener exchange.deregisterQueue(routingKey, this, arguments); if (isDurable() && exchange.isDurable()) { - _virtualHost.getMessageStore().unbindQueue(exchange, routingKey, this, arguments); + _virtualHost.getDurableConfigurationStore().unbindQueue(exchange, routingKey, this, arguments); } boolean removed = _bindings.remove(routingKey, arguments, exchange); @@ -295,11 +389,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _activeSubscriberCount.incrementAndGet(); subscription.setStateListener(this); - subscription.setLastSeenEntry(null, _entries.getHead()); + subscription.setQueueContext(new QueueContext(_entries.getHead())); if (!isDeleted()) { subscription.setQueue(this, exclusive); + if(_nolocal) + { + subscription.setNoLocal(_nolocal); + } _subscriptionList.add(subscription); if (isDeleted()) { @@ -329,17 +427,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener subscription.close(); // No longer can the queue have an exclusive consumer setExclusiveSubscriber(null); - - QueueEntry lastSeen; - - while ((lastSeen = subscription.getLastSeenEntry()) != null) - { - subscription.setLastSeenEntry(lastSeen, null); - } + subscription.setQueueContext(null); // auto-delete queues must be deleted if there are no remaining subscribers - if (_autoDelete && getConsumerCount() == 0) + if (_autoDelete && getConsumerCount() == 0 && !isExclusive()) { if (_logger.isInfoEnabled()) { @@ -358,7 +450,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Enqueue / Dequeue - public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException + public QueueEntry enqueue(ServerMessage message) throws AMQException { incrementQueueCount(); @@ -378,14 +470,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener entry = _entries.add(message); deliverToSubscription(exclusiveSub, entry); - - // where there is more than one producer there's a reasonable chance that even though there is - // no "queueing" we do not deliver because we get an interleving of _entries.add and - // deliverToSubscription between threads. Therefore have one more try. - if (!(entry.isAcquired() || entry.isDeleted())) - { - deliverToSubscription(exclusiveSub, entry); - } } finally { @@ -445,19 +529,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - if (entry.immediateAndNotDelivered()) - { - dequeue(storeContext, entry); - entry.dispose(storeContext); - } - else if (!(entry.isAcquired() || entry.isDeleted())) + + if (!(entry.isAcquired() || entry.isDeleted())) { checkSubscriptionsNotAheadOfDelivery(entry); deliverAsync(); } - _managedObject.checkForNotification(entry.getMessage()); + if(_managedObject != null) + { + _managedObject.checkForNotification(entry.getMessage()); + } return entry; } @@ -474,17 +557,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { if (!sub.wouldSuspend(entry)) { - if (!sub.isBrowser() && !entry.acquire(sub)) + if (sub.acquires() && !entry.acquire(sub)) { // restore credit here that would have been taken away by wouldSuspend since we didn't manage // to acquire the entry for this subscription - sub.restoreCredit(entry); + sub.onDequeue(entry); } else { - deliverMessage(sub, entry); - } } } @@ -501,7 +582,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // Simple Queues don't :-) } - private void incrementQueueSize(final AMQMessage message) + private void incrementQueueSize(final ServerMessage message) { getAtomicQueueSize().addAndGet(message.getSize()); } @@ -515,76 +596,48 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener throws AMQException { _deliveredMessages.incrementAndGet(); - if (_logger.isDebugEnabled()) - { - _logger.debug(sub + ": deliverMessage: " + entry.debugIdentity()); - } sub.send(entry); + + setLastSeenEntry(sub,entry); } - private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) + private boolean subscriptionReadyAndHasInterest(final Subscription sub, final QueueEntry entry) throws AMQException { + return sub.hasInterest(entry) && (getNextAvailableEntry(sub) == entry); + } - // We need to move this subscription on, past entries which are already acquired, or deleted or ones it has no - // interest in. - QueueEntry node = sub.getLastSeenEntry(); - while (node != null && (node.isAcquired() || node.isDeleted() || !sub.hasInterest(node))) - { - - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - else - { - node = null; - break; - } - } + private void setLastSeenEntry(final Subscription sub, final QueueEntry entry) + { + QueueContext subContext = (QueueContext) sub.getQueueContext(); + QueueEntry releasedEntry = subContext._releasedEntry; - if (node == entry) + QueueContext._lastSeenUpdater.set(subContext, entry); + if(releasedEntry == entry) { - // If the first entry that subscription can process is the one we are trying to deliver to it, then we are - // good - return true; - } - else - { - // Otherwise we should try to update the subscription's last seen entry to the entry we got to, providing - // no-one else has updated it to something furhter on in the list - //TODO - check - //updateLastSeenEntry(sub, entry); - return false; + QueueContext._releasedUpdater.compareAndSet(subContext, releasedEntry, null); } - } - private void updateLastSeenEntry(final Subscription sub, final QueueEntry entry) + private void updateSubRequeueEntry(final Subscription sub, final QueueEntry entry) { - QueueEntry node = sub.getLastSeenEntry(); - if (node != null && entry.compareTo(node) < 0 && sub.hasInterest(entry)) + QueueContext subContext = (QueueContext) sub.getQueueContext(); + if(subContext != null) { - do + QueueEntry oldEntry; + + while((oldEntry = subContext._releasedEntry) == null || oldEntry.compareTo(entry) > 0) { - if (sub.setLastSeenEntry(node, entry)) - { - return; - } - else + if(QueueContext._releasedUpdater.compareAndSet(subContext, oldEntry, entry)) { - node = sub.getLastSeenEntry(); + break; } } - while (node != null && entry.compareTo(node) < 0); } - } - public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException + public void requeue(QueueEntry entry) { SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); @@ -594,9 +647,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener Subscription sub = subscriberIter.getNode().getSubscription(); // we don't make browsers send the same stuff twice - if (!sub.isBrowser()) + if (sub.seesRequeues()) { - updateLastSeenEntry(sub, entry); + updateSubRequeueEntry(sub, entry); } } @@ -604,36 +657,31 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException + public void requeue(QueueEntryImpl entry, Subscription subscription) { - decrementQueueCount(); - decrementQueueSize(entry); - if (entry.acquiredBySubscription()) + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards + while (subscriberIter.advance()) { - _deliveredMessages.decrementAndGet(); - } + Subscription sub = subscriberIter.getNode().getSubscription(); - try - { - AMQMessage msg = entry.getMessage(); - if (msg.isPersistent()) + // we don't make browsers send the same stuff twice + if (sub.seesRequeues() && (!sub.acquires() && sub == subscription)) { - _virtualHost.getMessageStore().dequeueMessage(storeContext, this, msg.getMessageId()); + updateSubRequeueEntry(sub, entry); } - //entry.dispose(storeContext); - - } - catch (MessageCleanupException e) - { - // Message was dequeued, but could not then be deleted - // though it is no longer referenced. This should be very - // rare and can be detected and cleaned up on recovery or - // done through some form of manual intervention. - _logger.error(e, e); } - catch (AMQException e) + + deliverAsync(); + } + + public void dequeue(QueueEntry entry) + { + decrementQueueCount(); + decrementQueueSize(entry); + if (entry.acquiredBySubscription()) { - throw new FailedDequeueException(_name.toString(), e); + _deliveredMessages.decrementAndGet(); } checkCapacity(); @@ -811,7 +859,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); + final long messageId = entry.getMessage().getMessageNumber(); return messageId >= fromMessageId && messageId <= toMessageId; } @@ -830,7 +878,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean accept(QueueEntry entry) { - _complete = entry.getMessage().getMessageId() == messageId; + _complete = entry.getMessage().getMessageNumber() == messageId; return _complete; } @@ -872,7 +920,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter() { private long position = 0; - + public boolean accept(QueueEntry entry) { position++; @@ -884,25 +932,25 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener return position >= toPosition; } }); - + return entries; } public void moveMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, - StoreContext storeContext) + ServerTransaction txn) { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - MessageStore store = getVirtualHost().getMessageStore(); + final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); + List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter() { public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); + final long messageId = entry.getMessage().getMessageNumber(); return (messageId >= fromMessageId) && (messageId <= toMessageId) && entry.acquire(); @@ -914,61 +962,48 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } }); - try + + + // Move the messages in on the message store. + for (final QueueEntry entry : entries) { - store.beginTran(storeContext); + final ServerMessage message = entry.getMessage(); + txn.enqueue(toQueue, message, + new ServerTransaction.Action() + { - // Move the messages in on the message store. - for (QueueEntry entry : entries) - { - AMQMessage message = entry.getMessage(); + public void postCommit() + { + try + { + toQueue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } - if (message.isPersistent() && toQueue.isDurable()) - { - store.enqueueMessage(storeContext, toQueue, message.getMessageId()); - } - // dequeue does not decrement the refence count - entry.dequeue(storeContext); - } + public void onRollback() + { + entry.release(); + } + }); + txn.dequeue(this, message, + new ServerTransaction.Action() + { - // Commit and flush the move transcations. - try - { - store.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - } - catch (AMQException e) - { - try - { - store.abortTran(storeContext); - } - catch (AMQException rollbackEx) - { - _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); - } - throw new RuntimeException(e); - } + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + + } + }); - try - { - for (QueueEntry entry : entries) - { - toQueue.enqueue(storeContext, entry.getMessage()); - entry.delete(); - } - } - catch (MessageCleanupException e) - { - throw new RuntimeException(e); - } - catch (AMQException e) - { - throw new RuntimeException(e); } } @@ -976,27 +1011,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void copyMessagesToAnotherQueue(final long fromMessageId, final long toMessageId, String queueName, - final StoreContext storeContext) + final ServerTransaction txn) { - AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); - MessageStore store = getVirtualHost().getMessageStore(); + final AMQQueue toQueue = getVirtualHost().getQueueRegistry().getQueue(new AMQShortString(queueName)); List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter() { public boolean accept(QueueEntry entry) { - final long messageId = entry.getMessage().getMessageId(); - if ((messageId >= fromMessageId) - && (messageId <= toMessageId)) - { - if (!entry.isDeleted()) - { - return entry.getMessage().incrementReference(); - } - } - - return false; + final long messageId = entry.getMessage().getMessageNumber(); + return ((messageId >= fromMessageId) + && (messageId <= toMessageId)); } public boolean filterComplete() @@ -1005,98 +1031,69 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } }); - try + + // Move the messages in on the message store. + for (QueueEntry entry : entries) { - store.beginTran(storeContext); + final ServerMessage message = entry.getMessage(); - // Move the messages in on the message store. - for (QueueEntry entry : entries) + if (message.isPersistent() && toQueue.isDurable()) { - AMQMessage message = entry.getMessage(); - if (message.isReferenced() && message.isPersistent() && toQueue.isDurable()) - { - store.enqueueMessage(storeContext, toQueue, message.getMessageId()); - } - } + txn.enqueue(toQueue, message, new ServerTransaction.Action() + { + public void postCommit() + { + try + { + toQueue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } - // Commit and flush the move transcations. - try - { - store.commitTran(storeContext); - } - catch (AMQException e) - { - throw new RuntimeException("Failed to commit transaction whilst moving messages on message store.", e); - } - } - catch (AMQException e) - { - try - { - store.abortTran(storeContext); - } - catch (AMQException rollbackEx) - { - _logger.error("Failed to rollback transaction when error occured moving messages", rollbackEx); - } - throw new RuntimeException(e); - } + public void onRollback() + { + + } + }); - try - { - for (QueueEntry entry : entries) - { - if (entry.getMessage().isReferenced()) - { - toQueue.enqueue(storeContext, entry.getMessage()); - } } } - catch (MessageCleanupException e) - { - throw new RuntimeException(e); - } - catch (AMQException e) - { - throw new RuntimeException(e); - } } - public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + public void removeMessagesFromQueue(long fromMessageId, long toMessageId) { - try + QueueEntryIterator queueListIterator = _entries.iterator(); + + while (queueListIterator.advance()) { - QueueEntryIterator queueListIterator = _entries.iterator(); + QueueEntry node = queueListIterator.getNode(); - while (queueListIterator.advance()) + final ServerMessage message = node.getMessage(); + if(message != null) { - QueueEntry node = queueListIterator.getNode(); - - final long messageId = node.getMessage().getMessageId(); + final long messageId = message.getMessageNumber(); if ((messageId >= fromMessageId) && (messageId <= toMessageId) && !node.isDeleted() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node); } - } } - catch (AMQException e) - { - throw new RuntimeException(e); - } } // ------ Management functions - public void deleteMessageFromTop(StoreContext storeContext) throws AMQException + public void deleteMessageFromTop() { QueueEntryIterator queueListIterator = _entries.iterator(); boolean noDeletes = true; @@ -1106,33 +1103,62 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node); noDeletes = false; } } } - public long clearQueue(StoreContext storeContext) throws AMQException + public long clearQueue() { QueueEntryIterator queueListIterator = _entries.iterator(); long count = 0; + ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); + while (queueListIterator.advance()) { QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node, txn); count++; } } + + txn.commit(); + return count; } + private void dequeueEntry(final QueueEntry node) + { + ServerTransaction txn = new AutoCommitTransaction(getVirtualHost().getTransactionLog()); + dequeueEntry(node, txn); + } + + private void dequeueEntry(final QueueEntry node, ServerTransaction txn) + { + txn.dequeue(this, node.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + node.discard(); + } + + public void onRollback() + { + + } + }); + } + public void addQueueDeleteTask(final Task task) { _deleteTaskList.add(task); @@ -1157,7 +1183,111 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _bindings.deregister(); _virtualHost.getQueueRegistry().unregisterQueue(_name); - _managedObject.unregister(); + List<QueueEntry> entries = getMessagesOnTheQueue(new QueueEntryFilter() + { + + public boolean accept(QueueEntry entry) + { + return entry.acquire(); + } + + public boolean filterComplete() + { + return false; + } + }); + + ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); + + if(_alternateExchange != null) + { + + InboundMessageAdapter adapter = new InboundMessageAdapter(); + for(final QueueEntry entry : entries) + { + adapter.setEntry(entry); + final List<AMQQueue> rerouteQueues = _alternateExchange.route(adapter); + final ServerMessage message = entry.getMessage(); + if(rerouteQueues != null & rerouteQueues.size() != 0) + { + txn.enqueue(rerouteQueues, entry.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + try + { + for(AMQQueue queue : rerouteQueues) + { + QueueEntry entry = queue.enqueue(message); + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public void onRollback() + { + + } + }); + txn.dequeue(this, entry.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + } + }); + } + + } + + _alternateExchange.removeReference(this); + } + else + { + // TODO log discard + + for(final QueueEntry entry : entries) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + txn.dequeue(this, message, + new ServerTransaction.Action() + { + + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + } + }); + } + } + } + + txn.commit(); + + + if(_managedObject!=null) + { + _managedObject.unregister(); + } + for (Task task : _deleteTaskList) { task.doTask(this); @@ -1165,7 +1295,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.clear(); stop(); - + //Log Queue Deletion CurrentActor.get().message(_logSubject, QueueMessages.QUE_1002()); @@ -1249,7 +1379,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void deliverAsync(Subscription sub) { - _asyncDelivery.execute(new SubFlushRunner(sub)); + SubFlushRunner flusher = (SubFlushRunner) sub.get(SUB_FLUSH_RUNNER); + if(flusher == null) + { + flusher = new SubFlushRunner(sub); + sub.set(SUB_FLUSH_RUNNER, flusher); + } + _asyncDelivery.execute(flusher); } @@ -1298,66 +1434,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - private class SubFlushRunner implements ReadWriteRunnable - { - private final Subscription _sub; - - public SubFlushRunner(Subscription sub) - { - _sub = sub; - } - - public void run() - { - - String originalName = Thread.currentThread().getName(); - try{ - Thread.currentThread().setName("SubFlushRunner-"+_sub); - - boolean complete = false; - try - { - CurrentActor.set(_sub.getLogActor()); - complete = flushSubscription(_sub, new Long(MAX_ASYNC_DELIVERIES)); - - } - catch (AMQException e) - { - _logger.error(e); - } - finally - { - CurrentActor.remove(); - } - if (!complete && !_sub.isSuspended()) - { - _asyncDelivery.execute(this); - } - } - finally - { - Thread.currentThread().setName(originalName); - } - - } - - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - } - public void flushSubscription(Subscription sub) throws AMQException { flushSubscription(sub, Long.MAX_VALUE); } - public boolean flushSubscription(Subscription sub, Long iterations) throws AMQException + public boolean flushSubscription(Subscription sub, long iterations) throws AMQException { boolean atTail = false; @@ -1371,8 +1453,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { unregisterSubscription(sub); - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + sub.confirmAutoClose(); + } else if (!atTail) { @@ -1408,41 +1490,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private boolean attemptDelivery(Subscription sub) throws AMQException { boolean atTail = false; - boolean advanced = false; + boolean subActive = sub.isActive() && !sub.isSuspended(); if (subActive) { - QueueEntry node = moveSubscriptionToNextNode(sub); - if (_logger.isDebugEnabled()) - { - _logger.debug(sub + ": attempting Delivery: " + node.debugIdentity()); - } - if (!(node.isAcquired() || node.isDeleted())) + + QueueEntry node = getNextAvailableEntry(sub); + + if (node != null && !(node.isAcquired() || node.isDeleted())) { if (sub.hasInterest(node)) { if (!sub.wouldSuspend(node)) { - if (!sub.isBrowser() && !node.acquire(sub)) + if (sub.acquires() && !node.acquire(sub)) { - sub.restoreCredit(node); + sub.onDequeue(node); } else { deliverMessage(sub, node); - - if (sub.isBrowser()) - { - QueueEntry newNode = _entries.next(node); - - if (newNode != null) - { - advanced = true; - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - - } } } @@ -1450,29 +1517,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { //QPID-1187 - Treat the subscription as suspended for this message // and wait for the message to be removed to continue delivery. - - // 2009-09-30 : MR : setting subActive = false only causes, this - // particular delivery attempt to end. This is called from - // flushSubscription and processQueue both of which attempt - // delivery a number of times. Won't a bytes limited - // subscriber with not enough credit for the next message - // create a lot of new QELs? How about a browser that calls - // this method LONG.MAX_LONG times! subActive = false; - node.addStateChangeListener(new QueueEntryListener(sub, node)); - } - } - else - { - // this subscription is not interested in this node so we can skip over it - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); + node.addStateChangeListener(new QueueEntryListener(sub)); } } + } - atTail = (_entries.next(node) == null) && !advanced; + atTail = (node == null) || (_entries.next(node) == null); } return atTail || !subActive; } @@ -1484,46 +1535,58 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { SubscriptionList.SubscriptionNode subNode = subscriberIter.getNode(); Subscription sub = subNode.getSubscription(); - moveSubscriptionToNextNode(sub); + if(sub.acquires()) + { + getNextAvailableEntry(sub); + } + else + { + // TODO + } } } - private QueueEntry moveSubscriptionToNextNode(final Subscription sub) + private QueueEntry getNextAvailableEntry(final Subscription sub) throws AMQException { - QueueEntry node = sub.getLastSeenEntry(); - - while (node != null && (node.isAcquired() || node.isDeleted() || node.expired())) + QueueContext context = (QueueContext) sub.getQueueContext(); + if(context != null) { - if (!node.isAcquired() && !node.isDeleted() && node.expired()) + QueueEntry lastSeen = context._lastSeenEntry; + QueueEntry releasedNode = context._releasedEntry; + + QueueEntry node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen); + + boolean expired = false; + while (node != null && (node.isAcquired() || node.isDeleted() || (expired = node.expired()) || !sub.hasInterest(node))) { - if (node.acquire()) + if (expired) { - final StoreContext reapingStoreContext = new StoreContext(); - node.discard(reapingStoreContext); + expired = false; + if (node.acquire()) + { + dequeueEntry(node); + } } - } - QueueEntry newNode = _entries.next(node); - if (newNode != null) - { - sub.setLastSeenEntry(node, newNode); - node = sub.getLastSeenEntry(); - } - else - { - break; - } - } + if(QueueContext._lastSeenUpdater.compareAndSet(context, lastSeen, node)) + { + QueueContext._releasedUpdater.compareAndSet(context, releasedNode, null); + } - if (_logger.isDebugEnabled()) + lastSeen = context._lastSeenEntry; + releasedNode = context._releasedEntry; + node = (releasedNode != null && lastSeen.compareTo(releasedNode)>0) ? releasedNode : _entries.next(lastSeen); + } + return node; + } + else { - _logger.debug(sub + ": nextNode: " + (node == null ? "null" : node.debugIdentity())); + return null; } - - return node; } + private void processQueue(Runnable runner) throws AMQException { long stateChangeCount; @@ -1563,7 +1626,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener sub.getSendLock(); try { - done = attemptDelivery(sub); + if (sub != null) + { + done = attemptDelivery(sub); + } if (done) { if (extraLoops == 0) @@ -1573,8 +1639,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { unregisterSubscription(sub); - ProtocolOutputConverter converter = sub.getChannel().getProtocolSession().getProtocolOutputConverter(); - converter.confirmConsumerAutoClose(sub.getChannel().getChannelId(), sub.getConsumerTag()); + sub.confirmAutoClose(); } } else @@ -1611,8 +1676,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void checkMessageStatus() throws AMQException { - final StoreContext storeContext = new StoreContext(); - QueueEntryIterator queueListIterator = _entries.iterator(); while (queueListIterator.advance()) @@ -1620,11 +1683,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = queueListIterator.getNode(); if (!node.isDeleted() && node.expired() && node.acquire()) { - node.discard(storeContext); + dequeueEntry(node); } else { - _managedObject.checkForNotification(node.getMessage()); + if(_managedObject!=null) + { + _managedObject.checkForNotification(node.getMessage()); + } } } @@ -1748,23 +1814,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private final class QueueEntryListener implements QueueEntry.StateChangeListener { - private final QueueEntry _entry; + private final Subscription _sub; - public QueueEntryListener(final Subscription sub, final QueueEntry entry) + public QueueEntryListener(final Subscription sub) { - _entry = entry; _sub = sub; } public boolean equals(Object o) { - return _entry == ((QueueEntryListener) o)._entry && _sub == ((QueueEntryListener) o)._sub; + return _sub == ((QueueEntryListener) o)._sub; } public int hashCode() { - return System.identityHashCode(_entry) ^ System.identityHashCode(_sub); + return System.identityHashCode(_sub); } public void stateChanged(QueueEntry entry, QueueEntry.State oldSate, QueueEntry.State newState) @@ -1791,11 +1856,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener for (int i = 0; i < num && !it.atTail(); i++) { it.advance(); - ids.add(it.getNode().getMessage().getMessageId()); + ids.add(it.getNode().getMessage().getMessageNumber()); } return ids; } + public Object getExclusiveOwner() + { + return _exclusiveOwner; + } + + public void setExclusiveOwner(Object exclusiveOwner) + { + _exclusiveOwner = exclusiveOwner; + } + + public void configure(QueueConfiguration config) { if (config != null) @@ -1809,4 +1885,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _flowResumeCapacity = config.getFlowResumeCapacity(); } } + + public String getResourceName() + { + return _resourceName; + } + + + @Override + public String toString() + { + return String.valueOf(getName()); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java index a46c5ae2e8..d27a5ed234 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java @@ -1,6 +1,10 @@ package org.apache.qpid.server.queue; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.message.ServerMessage; + import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.concurrent.atomic.AtomicLong; /* * @@ -24,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; */ public class SimpleQueueEntryList implements QueueEntryList { + private final QueueEntryImpl _head; private volatile QueueEntryImpl _tail; @@ -40,9 +45,7 @@ public class SimpleQueueEntryList implements QueueEntryList _nextUpdater = AtomicReferenceFieldUpdater.newUpdater (QueueEntryImpl.class, QueueEntryImpl.class, "_next"); - - - + private AtomicLong _deletes = new AtomicLong(0L); public SimpleQueueEntryList(AMQQueue queue) @@ -52,21 +55,77 @@ public class SimpleQueueEntryList implements QueueEntryList _tail = _head; } + + void advanceHead() { + _deletes.incrementAndGet(); QueueEntryImpl head = _head.nextNode(); + boolean deleted = head.isDeleted(); while(head._next != null && head.isDeleted()) { + deleted = true; final QueueEntryImpl newhead = head.nextNode(); if(newhead != null) { - _nextUpdater.compareAndSet(_head,head, newhead); + if(_nextUpdater.compareAndSet(_head,head, newhead)) + { + _deletes.decrementAndGet(); + } } head = _head.nextNode(); } + + if(!deleted) + { + deleted = true; + } + + if(_deletes.get() > 1000L) + { + _deletes.set(0L); + scavenge(); + } } + void scavenge() + { + QueueEntryImpl root = _head; + QueueEntryImpl next = root.nextNode(); + + do + { + + + while(next._next != null && next.isDeleted()) + { + + final QueueEntryImpl newhead = next.nextNode(); + if(newhead != null) + { + _nextUpdater.compareAndSet(root,next, newhead); + } + next = root.nextNode(); + } + if(next._next != null) + { + if(!next.isDeleted()) + { + root = next; + next = root.nextNode(); + } + } + else + { + break; + } + + } while (next != null && next._next != null); + + } + + public AMQQueue getQueue() { @@ -74,7 +133,7 @@ public class SimpleQueueEntryList implements QueueEntryList } - public QueueEntry add(AMQMessage message) + public QueueEntry add(ServerMessage message) { QueueEntryImpl node = new QueueEntryImpl(this, message); for (;;) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java new file mode 100755 index 0000000000..547365f647 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java @@ -0,0 +1,68 @@ +package org.apache.qpid.server.queue; + +import org.apache.qpid.pool.ReadWriteRunnable; +import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + + +class SubFlushRunner implements ReadWriteRunnable +{ + private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + + + private final Subscription _sub; + private final String _name; + private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES; + + public SubFlushRunner(Subscription sub) + { + _sub = sub; + _name = "SubFlushRunner-"+_sub; + } + + public void run() + { + + + Thread.currentThread().setName(_name); + + boolean complete = false; + try + { + CurrentActor.set(_sub.getLogActor()); + complete = getQueue().flushSubscription(_sub, ITERATIONS); + + } + catch (AMQException e) + { + _logger.error(e); + } + finally + { + CurrentActor.remove(); + } + if (!complete && !_sub.isSuspended()) + { + getQueue().execute(this); + } + + + } + + private SimpleAMQQueue getQueue() + { + return (SimpleAMQQueue) _sub.getQueue(); + } + + public boolean isRead() + { + return false; + } + + public boolean isWrite() + { + return true; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java deleted file mode 100644 index b09283b11f..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/TransientMessageData.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.LinkedList; -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; - -/** - * Contains data that is only used in AMQMessage transiently, e.g. while the content - * body fragments are arriving. - * - * Having this data stored in a separate class means that the AMQMessage class avoids - * the small overhead of numerous guaranteed-null references. - * - * @author Apache Software Foundation - */ -public class TransientMessageData -{ - /** - * Stored temporarily until the header has been received at which point it is used when - * constructing the handle - */ - private MessagePublishInfo _messagePublishInfo; - - /** - * Also stored temporarily. - */ - private ContentHeaderBody _contentHeaderBody; - - /** - * Keeps a track of how many bytes we have received in body frames - */ - private long _bodyLengthReceived = 0; - - /** - * This is stored during routing, to know the queues to which this message should immediately be - * delivered. It is <b>cleared after delivery has been attempted</b>. Any persistent record of destinations is done - * by the message handle. - */ - private List<AMQQueue> _destinationQueues; - - public MessagePublishInfo getMessagePublishInfo() - { - return _messagePublishInfo; - } - - public void setMessagePublishInfo(MessagePublishInfo messagePublishInfo) - { - _messagePublishInfo = messagePublishInfo; - } - - public List<AMQQueue> getDestinationQueues() - { - return _destinationQueues == null ? (List<AMQQueue>) Collections.EMPTY_LIST : _destinationQueues; - } - - public void setDestinationQueues(List<AMQQueue> destinationQueues) - { - _destinationQueues = destinationQueues; - } - - public ContentHeaderBody getContentHeaderBody() - { - return _contentHeaderBody; - } - - public void setContentHeaderBody(ContentHeaderBody contentHeaderBody) - { - _contentHeaderBody = contentHeaderBody; - } - - public long getBodyLengthReceived() - { - return _bodyLengthReceived; - } - - public void addBodyLength(int value) - { - _bodyLengthReceived += value; - } - - public boolean isAllContentReceived() throws AMQException - { - return _bodyLengthReceived == _contentHeaderBody.bodySize; - } - - public void addDestinationQueue(AMQQueue queue) - { - if(_destinationQueues == null) - { - _destinationQueues = new ArrayList<AMQQueue>(); - } - _destinationQueues.add(queue); - } - - public boolean isPersistent() - { - return _contentHeaderBody.properties instanceof BasicContentHeaderProperties && - ((BasicContentHeaderProperties) _contentHeaderBody.properties).getDeliveryMode() == - BasicContentHeaderProperties.PERSISTENT; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java deleted file mode 100644 index 3ed8b0e55c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/WeakReferenceMessageHandle.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - * @author Robert Greig (robert.j.greig@jpmorgan.com) - */ -public class WeakReferenceMessageHandle implements AMQMessageHandle -{ - private WeakReference<ContentHeaderBody> _contentHeaderBody; - - private WeakReference<MessagePublishInfo> _messagePublishInfo; - - private List<WeakReference<ContentChunk>> _contentBodies; - - private boolean _redelivered; - - private final MessageStore _messageStore; - - private final Long _messageId; - private long _arrivalTime; - - public WeakReferenceMessageHandle(final Long messageId, MessageStore messageStore) - { - _messageId = messageId; - _messageStore = messageStore; - } - - public ContentHeaderBody getContentHeaderBody(StoreContext context) throws AMQException - { - ContentHeaderBody chb = (_contentHeaderBody != null ? _contentHeaderBody.get() : null); - if (chb == null) - { - MessageMetaData mmd = loadMessageMetaData(context); - chb = mmd.getContentHeaderBody(); - } - return chb; - } - - public Long getMessageId() - { - return _messageId; - } - - private MessageMetaData loadMessageMetaData(StoreContext context) - throws AMQException - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); - populateFromMessageMetaData(mmd); - return mmd; - } - - private void populateFromMessageMetaData(MessageMetaData mmd) - { - _arrivalTime = mmd.getArrivalTime(); - _contentHeaderBody = new WeakReference<ContentHeaderBody>(mmd.getContentHeaderBody()); - _messagePublishInfo = new WeakReference<MessagePublishInfo>(mmd.getMessagePublishInfo()); - } - - public int getBodyCount(StoreContext context) throws AMQException - { - if (_contentBodies == null) - { - MessageMetaData mmd = _messageStore.getMessageMetaData(context, _messageId); - int chunkCount = mmd.getContentChunkCount(); - _contentBodies = new ArrayList<WeakReference<ContentChunk>>(chunkCount); - for (int i = 0; i < chunkCount; i++) - { - _contentBodies.add(new WeakReference<ContentChunk>(null)); - } - } - return _contentBodies.size(); - } - - public long getBodySize(StoreContext context) throws AMQException - { - return getContentHeaderBody(context).bodySize; - } - - public ContentChunk getContentChunk(StoreContext context, int index) throws AMQException, IllegalArgumentException - { - if (index > _contentBodies.size() - 1) - { - throw new IllegalArgumentException("Index " + index + " out of valid range 0 to " + - (_contentBodies.size() - 1)); - } - WeakReference<ContentChunk> wr = _contentBodies.get(index); - ContentChunk cb = wr.get(); - if (cb == null) - { - cb = _messageStore.getContentBodyChunk(context, _messageId, index); - _contentBodies.set(index, new WeakReference<ContentChunk>(cb)); - } - return cb; - } - - /** - * Content bodies are set <i>before</i> the publish and header frames - * - * @param storeContext - * @param contentChunk - * @param isLastContentBody - * @throws AMQException - */ - public void addContentBodyFrame(StoreContext storeContext, ContentChunk contentChunk, boolean isLastContentBody) throws AMQException - { - if (_contentBodies == null && isLastContentBody) - { - _contentBodies = new ArrayList<WeakReference<ContentChunk>>(1); - } - else - { - if (_contentBodies == null) - { - _contentBodies = new LinkedList<WeakReference<ContentChunk>>(); - } - } - _contentBodies.add(new WeakReference<ContentChunk>(contentChunk)); - _messageStore.storeContentBodyChunk(storeContext, _messageId, _contentBodies.size() - 1, - contentChunk, isLastContentBody); - } - - public MessagePublishInfo getMessagePublishInfo(StoreContext context) throws AMQException - { - MessagePublishInfo bpb = (_messagePublishInfo != null ? _messagePublishInfo.get() : null); - if (bpb == null) - { - MessageMetaData mmd = loadMessageMetaData(context); - - bpb = mmd.getMessagePublishInfo(); - } - return bpb; - } - - public boolean isRedelivered() - { - return _redelivered; - } - - public void setRedelivered(boolean redelivered) - { - _redelivered = redelivered; - } - - public boolean isPersistent() - { - return true; - } - - /** - * This is called when all the content has been received. - * - * @param publishBody - * @param contentHeaderBody - * @throws AMQException - */ - public void setPublishAndContentHeaderBody(StoreContext storeContext, MessagePublishInfo publishBody, - ContentHeaderBody contentHeaderBody) - throws AMQException - { - // if there are no content bodies the list will be null so we must - // create en empty list here - if (contentHeaderBody.bodySize == 0) - { - _contentBodies = new LinkedList<WeakReference<ContentChunk>>(); - } - - final long arrivalTime = System.currentTimeMillis(); - - - MessageMetaData mmd = new MessageMetaData(publishBody, contentHeaderBody, _contentBodies.size(), arrivalTime); - - _messageStore.storeMessageMetaData(storeContext, _messageId, mmd); - - - populateFromMessageMetaData(mmd); - } - - public void removeMessage(StoreContext storeContext) throws AMQException - { - _messageStore.removeMessage(storeContext, _messageId); - } - - public long getArrivalTime() - { - return _arrivalTime; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 831f928832..8e8581b66f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -35,8 +35,8 @@ import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import java.io.File; @@ -51,15 +51,15 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise(int instanceID) throws Exception { - _rootMessageLogger = new RootMessageLoggerImpl(_configuration, + _rootMessageLogger = new RootMessageLoggerImpl(_configuration, new Log4jMessageLogger()); - + _registryName = String.valueOf(instanceID); // Set the Actor for current log messages CurrentActor.set(new BrokerActor(_registryName, _rootMessageLogger)); - CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); + CurrentActor.get().message(BrokerMessages.BRK_1001(QpidProperties.getReleaseVersion(),QpidProperties.getBuildVersion())); initialiseManagedObjectRegistry(); @@ -68,7 +68,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _pluginManager = new PluginManager(_configuration.getPluginDirectory()); _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager); - + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(_configuration); _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); @@ -99,10 +99,10 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } private void initialiseVirtualHosts() throws Exception - { + { for (String name : _configuration.getVirtualHosts()) { - _virtualHostRegistry.registerVirtualHost(new VirtualHost(_configuration.getVirtualHostConfig(name))); + _virtualHostRegistry.registerVirtualHost(new VirtualHostImpl(_configuration.getVirtualHostConfig(name))); } getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java new file mode 100755 index 0000000000..7e93623cab --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/PrincipalHolder.java @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import java.security.Principal; + +public interface PrincipalHolder +{ + /** @return a Principal that was used to authorized this session */ + Principal getPrincipal(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java index 6f7f66fad2..af0a1944cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java @@ -14,9 +14,9 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.security.access; @@ -32,14 +32,11 @@ import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.SecurityConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.security.access.plugins.SimpleXML; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; public class ACLManager @@ -78,7 +75,7 @@ public class ACLManager { _hostPlugins = configurePlugins(hostConfig); } - + public Map<String, ACLPlugin> configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException { Configuration securityConfig = hostConfig.getConfiguration(); @@ -108,7 +105,7 @@ public class ACLManager } } return plugins; - } + } public static Logger getLogger() { @@ -131,18 +128,18 @@ public class ACLManager if (result == AuthzResult.DENIED) { // Something vetoed the access, we're done - return false; + return false; } else if (result == AuthzResult.ALLOWED) { - // Remove plugin from global check list since + // Remove plugin from global check list since // host allow overrides global allow remainingPlugins.remove(plugin.getKey()); } } - + for (ACLPlugin plugin : remainingPlugins.values()) - { + { result = checker.allowed(plugin); if (result == AuthzResult.DENIED) { @@ -152,7 +149,7 @@ public class ACLManager return true; } - public boolean authoriseBind(final AMQProtocolSession session, final Exchange exch, final AMQQueue queue, + public boolean authoriseBind(final PrincipalHolder session, final Exchange exch, final AMQQueue queue, final AMQShortString routingKey) { return checkAllPlugins(new AccessCheck() @@ -167,7 +164,7 @@ public class ACLManager }); } - public boolean authoriseConnect(final AMQProtocolSession session, final VirtualHost virtualHost) + public boolean authoriseConnect(final PrincipalHolder session, final VirtualHost virtualHost) { return checkAllPlugins(new AccessCheck() { @@ -181,7 +178,7 @@ public class ACLManager }); } - public boolean authoriseConsume(final AMQProtocolSession session, final boolean noAck, final AMQQueue queue) + public boolean authoriseConsume(final PrincipalHolder session, final boolean noAck, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() { @@ -195,7 +192,7 @@ public class ACLManager }); } - public boolean authoriseConsume(final AMQProtocolSession session, final boolean exclusive, final boolean noAck, + public boolean authoriseConsume(final PrincipalHolder session, final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() @@ -210,7 +207,7 @@ public class ACLManager }); } - public boolean authoriseCreateExchange(final AMQProtocolSession session, final boolean autoDelete, + public boolean authoriseCreateExchange(final PrincipalHolder session, final boolean autoDelete, final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, final boolean passive, final AMQShortString exchangeType) { @@ -227,7 +224,7 @@ public class ACLManager }); } - public boolean authoriseCreateQueue(final AMQProtocolSession session, final boolean autoDelete, + public boolean authoriseCreateQueue(final PrincipalHolder session, final boolean autoDelete, final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, final AMQShortString queue) { @@ -243,7 +240,7 @@ public class ACLManager }); } - public boolean authoriseDelete(final AMQProtocolSession session, final AMQQueue queue) + public boolean authoriseDelete(final PrincipalHolder session, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() { @@ -257,7 +254,7 @@ public class ACLManager }); } - public boolean authoriseDelete(final AMQProtocolSession session, final Exchange exchange) + public boolean authoriseDelete(final PrincipalHolder session, final Exchange exchange) { return checkAllPlugins(new AccessCheck() { @@ -270,8 +267,8 @@ public class ACLManager }); } - - public boolean authorisePublish(final AMQProtocolSession session, final boolean immediate, final boolean mandatory, + + public boolean authorisePublish(final PrincipalHolder session, final boolean immediate, final boolean mandatory, final AMQShortString routingKey, final Exchange e) { return checkAllPlugins(new AccessCheck() @@ -286,7 +283,7 @@ public class ACLManager }); } - public boolean authorisePurge(final AMQProtocolSession session, final AMQQueue queue) + public boolean authorisePurge(final PrincipalHolder session, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() { @@ -300,7 +297,7 @@ public class ACLManager }); } - public boolean authoriseUnbind(final AMQProtocolSession session, final Exchange exch, + public boolean authoriseUnbind(final PrincipalHolder session, final Exchange exch, final AMQShortString routingKey, final AMQQueue queue) { return checkAllPlugins(new AccessCheck() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java index 032184ec39..cf8a3fede9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java @@ -24,9 +24,9 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.PrincipalHolder; public interface ACLPlugin { @@ -34,37 +34,37 @@ public interface ACLPlugin { ALLOWED, DENIED, - ABSTAIN + ABSTAIN } void setConfiguration(Configuration config) throws ConfigurationException; - // These return true if the plugin thinks the action should be allowed, and false if not. - - AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey); + // These return true if the plugin thinks the action should be allowed, and false if not. - AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey); + + AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); - AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue); - AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost); + AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost); - AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue); + AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue); - AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue); - AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue); + AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue); - AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange); + AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange); - AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e); - AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue); + AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue); - AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue); + AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java index 6d35d7ae48..a299907e42 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalPermissions.java @@ -425,8 +425,9 @@ public class PrincipalPermissions // This will allow consumption from any temporary queue including ones not owned by this user. // Of course the exclusivity will not be broken. { + // if not limited to ownQueuesOnly then ok else check queue Owner. - return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; + return (!ownQueuesOnly || new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } } //if this is a temporary queue and the user does not have permissions for temporary queues then deny @@ -441,7 +442,7 @@ public class PrincipalPermissions // if no queues are listed then ALL are ok othereise it must be specified. if (ownQueuesOnly) { - if (queue.getOwner().equals(_user)) + if ( new AMQShortString(queue.getPrincipalHolder().getPrincipal().getName()).equals(_user)) { return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java index 682135bc25..f99f3a60f7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java @@ -22,76 +22,76 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.PrincipalHolder; /** - * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. + * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. */ public abstract class AbstractACLPlugin implements ACLPlugin { private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, + public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { return DEFAULT_ANSWER; } - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) { return DEFAULT_ANSWER; } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) { // TODO Auto-generated method stub return null; } - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { return DEFAULT_ANSWER; } - public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { return DEFAULT_ANSWER; } - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) { return DEFAULT_ANSWER; } - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, + public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { return DEFAULT_ANSWER; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java index ca6b68dafa..d0df354d78 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java @@ -21,46 +21,45 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQConnectionException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.access.ACLPlugin; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; public abstract class BasicACLPlugin implements ACLPlugin { - // Returns true or false if the plugin should authorise or deny the request + // Returns true or false if the plugin should authorise or deny the request protected abstract AuthzResult getResult(); - - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, + + public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { return getResult(); } - public AuthzResult authoriseConnect(AMQProtocolSession session, + public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) { return getResult(); } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) { - return getResult(); + return getResult(); } - public AuthzResult authoriseConsume(AMQProtocolSession session, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return getResult(); } - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, + public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) @@ -68,36 +67,36 @@ public abstract class BasicACLPlugin implements ACLPlugin return getResult(); } - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, + public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { return getResult(); } - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { return getResult(); } - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { return getResult(); } - public AuthzResult authorisePublish(AMQProtocolSession session, + public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { return getResult(); } - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) { return getResult(); } - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, + public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { return getResult(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 26a76c9af1..77d3c4bcdf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -54,7 +54,7 @@ public class DenyAll extends BasicACLPlugin if (ACLManager.getLogger().isInfoEnabled()) { ACLManager.getLogger().info( - "Denying user:" + session.getAuthorizedID()); + "Denying user:" + session.getPrincipal()); } throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "DenyAll Plugin"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index e299ce99c4..a5bdf662af 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -22,24 +22,16 @@ package org.apache.qpid.server.security.access.plugins; import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicConsumeBody; -import org.apache.qpid.framing.BasicPublishBody; -import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.security.access.PrincipalPermissions; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Map; @@ -64,7 +56,7 @@ public class SimpleXML implements ACLPlugin return plugin; } }; - + private Map<String, PrincipalPermissions> _users; private final AccessResult GRANTED = new AccessResult(this, AccessResult.AccessStatus.GRANTED); @@ -110,7 +102,7 @@ public class SimpleXML implements ACLPlugin /** * Publish format takes Exchange + Routing Key Pairs - * + * * @param config * XML Configuration */ @@ -349,9 +341,9 @@ public class SimpleXML implements ACLPlugin return "Simple"; } - public AuthzResult authoriseBind(AMQProtocolSession session, Exchange exch, AMQQueue queue, AMQShortString routingKey) + public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -362,9 +354,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -375,9 +367,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue) + public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -388,16 +380,16 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal, + public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, AMQQueue queue) { return authoriseConsume(session, noAck, queue); } - public AuthzResult authoriseCreateExchange(AMQProtocolSession session, boolean autoDelete, boolean durable, + public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -408,10 +400,10 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseCreateQueue(AMQProtocolSession session, boolean autoDelete, boolean durable, boolean exclusive, + public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -422,9 +414,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -435,9 +427,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -448,10 +440,10 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory, + public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, AMQShortString routingKey, Exchange e) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -462,9 +454,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; @@ -475,9 +467,9 @@ public class SimpleXML implements ACLPlugin } } - public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey, AMQQueue queue) + public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue) { - PrincipalPermissions principalPermissions = _users.get(session.getAuthorizedID().getName()); + PrincipalPermissions principalPermissions = _users.get(session.getPrincipal().getName()); if (principalPermissions == null) { return AuthzResult.DENIED; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java index 7450322130..17d80c63fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java @@ -31,10 +31,11 @@ import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.protocol.ProtocolEngine; import org.apache.qpid.server.security.access.ACLPlugin; import org.apache.qpid.server.security.access.ACLPluginFactory; import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.util.NetMatcher; @@ -57,7 +58,7 @@ public class FirewallPlugin extends AbstractACLPlugin return plugin; } }; - + public class FirewallRule { @@ -69,13 +70,13 @@ public class FirewallPlugin extends AbstractACLPlugin public FirewallRule(String access, List networks, List hostnames) { _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED; - + if (networks != null && networks.size() > 0) { String[] networkStrings = objListToStringArray(networks); _network = new NetMatcher(networkStrings); } - + if (hostnames != null && hostnames.size() > 0) { int i = 0; @@ -85,7 +86,7 @@ public class FirewallPlugin extends AbstractACLPlugin _hostnamePatterns[i++] = Pattern.compile(hostname); } } - + } private String[] objListToStringArray(List objList) @@ -147,7 +148,7 @@ public class FirewallPlugin extends AbstractACLPlugin thread.run(); long endTime = System.currentTimeMillis() + DNS_TIMEOUT; - + while (System.currentTimeMillis() < endTime && !done.get()) { try @@ -176,8 +177,15 @@ public class FirewallPlugin extends AbstractACLPlugin private FirewallRule[] _rules; @Override - public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost) + public AuthzResult authoriseConnect(PrincipalHolder principalHolder, VirtualHost virtualHost) { + if(!(principalHolder instanceof ProtocolEngine)) + { + return AuthzResult.ABSTAIN; // We only deal with tcp sessions + } + + ProtocolEngine session = (ProtocolEngine) principalHolder; + SocketAddress sockAddr = session.getRemoteAddress(); if (!(sockAddr instanceof InetSocketAddress)) { @@ -228,7 +236,7 @@ public class FirewallPlugin extends AbstractACLPlugin _default = AuthzResult.DENIED; } CompositeConfiguration finalConfig = new CompositeConfiguration(config); - + List subFiles = config.getList("xml[@fileName]"); for (Object subFile : subFiles) { @@ -236,7 +244,7 @@ public class FirewallPlugin extends AbstractACLPlugin } // all rules must have an access attribute - int numRules = finalConfig.getList("rule[@access]").size(); + int numRules = finalConfig.getList("rule[@access]").size(); _rules = new FirewallRule[numRules]; for (int i = 0; i < numRules; i++) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index e0d4c49af1..2619a69cfd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -215,14 +215,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab _logger.warn("Unable to load access file:" + jmxaccesssFile); } - try - { - _mbean.register(); - } - catch (AMQException e) - { - _logger.warn("Unable to register user management MBean"); - } + _mbean.register(); } catch (JMException e) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java index fd2d09b777..f8bc530aa6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/AbstractMessageStore.java @@ -31,12 +31,12 @@ public abstract class AbstractMessageStore implements MessageStore { protected LogSubject _logSubject; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration hostConfig) throws Exception + public void configure(VirtualHost virtualHost) throws Exception { _logSubject = new MessageStoreLogSubject(virtualHost, this); CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); } - + public void close() throws Exception { CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java new file mode 100755 index 0000000000..c7606832d0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java @@ -0,0 +1,57 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; +import org.apache.qpid.framing.FieldTable; + +public interface ConfigurationRecoveryHandler +{ + QueueRecoveryHandler begin(MessageStore store); + + public static interface QueueRecoveryHandler + { + void queue(String queueName, String owner, FieldTable arguments); + ExchangeRecoveryHandler completeQueueRecovery(); + } + + public static interface ExchangeRecoveryHandler + { + void exchange(String exchangeName, String type, boolean autoDelete); + BindingRecoveryHandler completeExchangeRecovery(); + } + + public static interface BindingRecoveryHandler + { + void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf); + void completeBindingRecovery(); + } + + public static interface QueueEntryRecoveryHandler + { + void complete(); + + void queueEntry(String queueName, long messageId); + } + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java index c014739324..ba5574d1fa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java @@ -21,28 +21,18 @@ package org.apache.qpid.server.store; import org.apache.log4j.Logger; -import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.MessageStoreMessages; -import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.commons.configuration.Configuration; + import java.io.ByteArrayInputStream; import java.io.File; @@ -56,15 +46,14 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; -public class DerbyMessageStore extends AbstractMessageStore +public class DerbyMessageStore implements MessageStore { private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); @@ -80,57 +69,66 @@ public class DerbyMessageStore extends AbstractMessageStore private static final String QUEUE_TABLE_NAME = "QPID_QUEUE"; private static final String BINDINGS_TABLE_NAME = "QPID_BINDINGS"; private static final String QUEUE_ENTRY_TABLE_NAME = "QPID_QUEUE_ENTRY"; - private static final String MESSAGE_META_DATA_TABLE_NAME = "QPID_MESSAGE_META_DATA"; + + private static final String META_DATA_TABLE_NAME = "QPID_META_DATA"; private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; private static final int DB_VERSION = 1; - private VirtualHost _virtualHost; private static Class<Driver> DRIVER_CLASS; - private final AtomicLong _messageId = new AtomicLong(1); + private final AtomicLong _messageId = new AtomicLong(0); private AtomicBoolean _closed = new AtomicBoolean(false); private String _connectionURL; - Map<AMQShortString, Integer> _queueRecoveries = new TreeMap<AMQShortString, Integer>(); - + private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; private static final String CREATE_DB_VERSION_TABLE = "CREATE TABLE "+DB_VERSION_TABLE_NAME+" ( version int not null )"; private static final String INSERT_INTO_DB_VERSION = "INSERT INTO "+DB_VERSION_TABLE_NAME+" ( version ) VALUES ( ? )"; + private static final String CREATE_EXCHANGE_TABLE = "CREATE TABLE "+EXCHANGE_TABLE_NAME+" ( name varchar(255) not null, type varchar(255) not null, autodelete SMALLINT not null, PRIMARY KEY ( name ) )"; private static final String CREATE_QUEUE_TABLE = "CREATE TABLE "+QUEUE_TABLE_NAME+" ( name varchar(255) not null, owner varchar(255), PRIMARY KEY ( name ) )"; private static final String CREATE_BINDINGS_TABLE = "CREATE TABLE "+BINDINGS_TABLE_NAME+" ( exchange_name varchar(255) not null, queue_name varchar(255) not null, binding_key varchar(255) not null, arguments blob , PRIMARY KEY ( exchange_name, queue_name, binding_key ) )"; - private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; - private static final String CREATE_MESSAGE_META_DATA_TABLE = "CREATE TABLE "+MESSAGE_META_DATA_TABLE_NAME+" ( message_id bigint not null, exchange_name varchar(255) not null, routing_key varchar(255), flag_mandatory smallint not null, flag_immediate smallint not null, content_header blob, chunk_count int not null, PRIMARY KEY ( message_id ) )"; - private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, chunk_id int not null, content_chunk blob , PRIMARY KEY (message_id, chunk_id) )"; private static final String SELECT_FROM_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME; private static final String FIND_QUEUE = "SELECT name, owner FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; private static final String SELECT_FROM_EXCHANGE = "SELECT name, type, autodelete FROM " + EXCHANGE_TABLE_NAME; private static final String SELECT_FROM_BINDINGS = - "SELECT queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ?"; + "SELECT exchange_name, queue_name, binding_key, arguments FROM " + BINDINGS_TABLE_NAME + " ORDER BY exchange_name"; private static final String FIND_BINDING = "SELECT * FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ? "; - private static final String DELETE_FROM_MESSAGE_META_DATA = "DELETE FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; - private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; private static final String INSERT_INTO_EXCHANGE = "INSERT INTO " + EXCHANGE_TABLE_NAME + " ( name, type, autodelete ) VALUES ( ?, ?, ? )"; private static final String DELETE_FROM_EXCHANGE = "DELETE FROM " + EXCHANGE_TABLE_NAME + " WHERE name = ?"; private static final String INSERT_INTO_BINDINGS = "INSERT INTO " + BINDINGS_TABLE_NAME + " ( exchange_name, queue_name, binding_key, arguments ) values ( ?, ?, ?, ? )"; private static final String DELETE_FROM_BINDINGS = "DELETE FROM " + BINDINGS_TABLE_NAME + " WHERE exchange_name = ? AND queue_name = ? AND binding_key = ?"; private static final String INSERT_INTO_QUEUE = "INSERT INTO " + QUEUE_TABLE_NAME + " (name, owner) VALUES (?, ?)"; private static final String DELETE_FROM_QUEUE = "DELETE FROM " + QUEUE_TABLE_NAME + " WHERE name = ?"; + + private static final String CREATE_QUEUE_ENTRY_TABLE = "CREATE TABLE "+QUEUE_ENTRY_TABLE_NAME+" ( queue_name varchar(255) not null, message_id bigint not null, PRIMARY KEY (queue_name, message_id) )"; private static final String INSERT_INTO_QUEUE_ENTRY = "INSERT INTO " + QUEUE_ENTRY_TABLE_NAME + " (queue_name, message_id) values (?,?)"; private static final String DELETE_FROM_QUEUE_ENTRY = "DELETE FROM " + QUEUE_ENTRY_TABLE_NAME + " WHERE queue_name = ? AND message_id =?"; - private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, chunk_id, content_chunk ) values (?, ?, ?)"; - private static final String INSERT_INTO_MESSAGE_META_DATA = "INSERT INTO " + MESSAGE_META_DATA_TABLE_NAME + "( message_id , exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count ) values (?, ?, ?, ?, ?, ?, ?)"; - private static final String SELECT_FROM_MESSAGE_META_DATA = - "SELECT exchange_name , routing_key , flag_mandatory , flag_immediate , content_header , chunk_count FROM " + MESSAGE_META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME + " ORDER BY queue_name, message_id"; + + + private static final String CREATE_META_DATA_TABLE = "CREATE TABLE "+META_DATA_TABLE_NAME+" ( message_id bigint not null, meta_data blob, PRIMARY KEY ( message_id ) )"; + private static final String CREATE_MESSAGE_CONTENT_TABLE = "CREATE TABLE "+MESSAGE_CONTENT_TABLE_NAME+" ( message_id bigint not null, offset int not null, last_byte int not null, content blob , PRIMARY KEY (message_id, offset) )"; + + private static final String INSERT_INTO_MESSAGE_CONTENT = "INSERT INTO " + MESSAGE_CONTENT_TABLE_NAME + "( message_id, offset, last_byte, content ) values (?, ?, ?, ?)"; private static final String SELECT_FROM_MESSAGE_CONTENT = - "SELECT content_chunk FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? and chunk_id = ?"; - private static final String SELECT_FROM_QUEUE_ENTRY = "SELECT queue_name, message_id FROM " + QUEUE_ENTRY_TABLE_NAME; - private static final String TABLE_EXISTANCE_QUERY = "SELECT 1 FROM SYS.SYSTABLES WHERE TABLENAME = ?"; + "SELECT offset, content FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ? AND last_byte > ? AND offset < ? ORDER BY message_id, offset"; + private static final String DELETE_FROM_MESSAGE_CONTENT = "DELETE FROM " + MESSAGE_CONTENT_TABLE_NAME + " WHERE message_id = ?"; + + private static final String INSERT_INTO_META_DATA = "INSERT INTO " + META_DATA_TABLE_NAME + "( message_id , meta_data ) values (?, ?)";; + private static final String SELECT_FROM_META_DATA = + "SELECT meta_data FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String DELETE_FROM_META_DATA = "DELETE FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?"; + private static final String SELECT_ALL_FROM_META_DATA = "SELECT message_id, meta_data FROM " + META_DATA_TABLE_NAME; + + + private LogSubject _logSubject; + private boolean _configured; private enum State @@ -146,21 +144,82 @@ public class DerbyMessageStore extends AbstractMessageStore private State _state = State.INITIAL; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception { - super.configure(virtualHost,base,config); - stateTransition(State.INITIAL, State.CONFIGURING); + _logSubject = logSubject; + CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName())); - initialiseDriver(); + if(!_configured) + { + commonConfiguration(name, storeConfiguration, logSubject); + _configured = true; + } + + // this recovers durable exchanges, queues, and bindings + recover(recoveryHandler); - _virtualHost = virtualHost; - _logger.info("Configuring Derby message store for virtual host " + virtualHost.getName()); - QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + stateTransition(State.RECOVERING, State.STARTED); + + } + + + public void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception + { + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + + if(!_configured) + { + + _logSubject = logSubject; + + commonConfiguration(name, storeConfiguration, logSubject); + _configured = true; + } + + recoverMessages(recoveryHandler); + + } + + + + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception + { + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1001(this.getClass().getName())); + + if(!_configured) + { + + _logSubject = logSubject; + + commonConfiguration(name, storeConfiguration, logSubject); + _configured = true; + } + + recoverQueueEntries(recoveryHandler); + + } + + + + private void commonConfiguration(String name, Configuration storeConfiguration, LogSubject logSubject) + throws ClassNotFoundException, SQLException + { + initialiseDriver(); //Update to pick up QPID_WORK and use that as the default location not just derbyDB - final String databasePath = config.getStoreConfiguration().getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); + + final String databasePath = storeConfiguration.getString(ENVIRONMENT_PATH_PROPERTY, System.getProperty("QPID_WORK")+"/derbyDB"); File environmentPath = new File(databasePath); if (!environmentPath.exists()) @@ -172,17 +231,9 @@ public class DerbyMessageStore extends AbstractMessageStore } } - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1002(environmentPath.getAbsolutePath())); - - createOrOpenDatabase(databasePath); - - // this recovers durable queues and persistent messages - - recover(); - - - stateTransition(State.RECOVERING, State.STARTED); + CurrentActor.get().message(logSubject, MessageStoreMessages.MST_1002(environmentPath.getAbsolutePath())); + createOrOpenDatabase(name, databasePath); } private static synchronized void initialiseDriver() throws ClassNotFoundException @@ -193,10 +244,10 @@ public class DerbyMessageStore extends AbstractMessageStore } } - private void createOrOpenDatabase(final String environmentPath) throws SQLException + private void createOrOpenDatabase(String name, final String environmentPath) throws SQLException { //fixme this the _vhost name should not be added here. - _connectionURL = "jdbc:derby:" + environmentPath + "/" + _virtualHost.getName() + ";create=true"; + _connectionURL = "jdbc:derby:" + environmentPath + "/" + name + ";create=true"; Connection conn = newConnection(); @@ -205,7 +256,7 @@ public class DerbyMessageStore extends AbstractMessageStore createQueueTable(conn); createBindingsTable(conn); createQueueEntryTable(conn); - createMessageMetaDataTable(conn); + createMetaDataTable(conn); createMessageContentTable(conn); conn.close(); @@ -276,12 +327,12 @@ public class DerbyMessageStore extends AbstractMessageStore } - private void createMessageMetaDataTable(final Connection conn) throws SQLException + private void createMetaDataTable(final Connection conn) throws SQLException { - if(!tableExists(MESSAGE_META_DATA_TABLE_NAME, conn)) + if(!tableExists(META_DATA_TABLE_NAME, conn)) { Statement stmt = conn.createStatement(); - stmt.execute(CREATE_MESSAGE_META_DATA_TABLE); + stmt.execute(CREATE_META_DATA_TABLE); stmt.close(); } @@ -314,38 +365,22 @@ public class DerbyMessageStore extends AbstractMessageStore return exists; } - public void recover() throws AMQException + public void recover(ConfigurationRecoveryHandler recoveryHandler) throws AMQException { stateTransition(State.CONFIGURING, State.RECOVERING); - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1004(null, false)); - - StoreContext context = new StoreContext(); try { - Map<AMQShortString, AMQQueue> queues = loadQueues(); - - recoverExchanges(); - - try - { - - beginTran(context); + ConfigurationRecoveryHandler.QueueRecoveryHandler qrh = recoveryHandler.begin(this); + List<String> queues = loadQueues(qrh); - deliverMessages(context, queues); - commitTran(context); + ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh = qrh.completeQueueRecovery(); + List<String> exchanges = loadExchanges(erh); + ConfigurationRecoveryHandler.BindingRecoveryHandler brh = erh.completeExchangeRecovery(); + recoverBindings(brh, exchanges); + brh.completeBindingRecovery(); - //Recovery Complete - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1006(null, false)); - } - finally - { - if(inTran(context)) - { - abortTran(context); - } - } } catch (SQLException e) @@ -357,53 +392,34 @@ public class DerbyMessageStore extends AbstractMessageStore } - private Map<AMQShortString, AMQQueue> loadQueues() throws SQLException, AMQException + private List<String> loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException, AMQException { Connection conn = newConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE); - Map<AMQShortString, AMQQueue> queueMap = new HashMap<AMQShortString, AMQQueue>(); + List<String> queues = new ArrayList<String>(); + while(rs.next()) { String queueName = rs.getString(1); String owner = rs.getString(2); - AMQShortString queueNameShortString = new AMQShortString(queueName); + qrh.queue(queueName, owner, null); - AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + queues.add(queueName); - if (q == null) - { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, - null); - _virtualHost.getQueueRegistry().registerQueue(q); - } - - queueMap.put(queueNameShortString,q); - - CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1004(String.valueOf(q.getName()), true)); - //Record that we have a queue for recovery - _queueRecoveries.put(new AMQShortString(queueName), 0); - - } - return queueMap; - } - private void recoverExchanges() throws AMQException, SQLException - { - for (Exchange exchange : loadExchanges()) - { - recoverExchange(exchange); } + return queues; } - private List<Exchange> loadExchanges() throws AMQException, SQLException + private List<String> loadExchanges(ConfigurationRecoveryHandler.ExchangeRecoveryHandler erh) throws AMQException, SQLException { - List<Exchange> exchanges = new ArrayList<Exchange>(); + List<String> exchanges = new ArrayList<String>(); Connection conn = null; try { @@ -413,21 +429,15 @@ public class DerbyMessageStore extends AbstractMessageStore Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_FROM_EXCHANGE); - Exchange exchange; while(rs.next()) { String exchangeName = rs.getString(1); String type = rs.getString(2); boolean autoDelete = rs.getShort(3) != 0; - AMQShortString exchangeNameSS = new AMQShortString(exchangeName); - exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeNameSS); - if (exchange == null) - { - exchange = _virtualHost.getExchangeFactory().createExchange(exchangeNameSS, new AMQShortString(type), true, autoDelete, 0); - _virtualHost.getExchangeRegistry().registerExchange(exchange); - } - exchanges.add(exchange); + exchanges.add(exchangeName); + + erh.exchange(exchangeName, type, autoDelete); } return exchanges; @@ -443,11 +453,13 @@ public class DerbyMessageStore extends AbstractMessageStore } - private void recoverExchange(Exchange exchange) throws AMQException, SQLException + private void recoverBindings(ConfigurationRecoveryHandler.BindingRecoveryHandler brh, List<String> exchanges) throws AMQException, SQLException { - _logger.info("Recovering durable exchange " + exchange.getName() + " of type " + exchange.getType() + "..."); - QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); + + _logger.info("Recovering bindings..."); + + Connection conn = null; try @@ -455,41 +467,29 @@ public class DerbyMessageStore extends AbstractMessageStore conn = newConnection(); PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_BINDINGS); - stmt.setString(1, exchange.getName().toString()); ResultSet rs = stmt.executeQuery(); while(rs.next()) { - String queueName = rs.getString(1); - String bindingKey = rs.getString(2); - Blob arguments = rs.getBlob(3); - + String exchangeName = rs.getString(1); + String queueName = rs.getString(2); + String bindingKey = rs.getString(3); + Blob arguments = rs.getBlob(4); + java.nio.ByteBuffer buf; - AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue == null) + if(arguments != null && arguments.length() != 0) { - _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " - + exchange.getName()); + byte[] argumentBytes = arguments.getBytes(1, (int) arguments.length()); + buf = java.nio.ByteBuffer.wrap(argumentBytes); } else { - _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName - + ", Routing Key: " + bindingKey + ", Arguments: " + arguments - + ")"); - - FieldTable argumentsFT = null; - if(arguments != null) - { - byte[] argumentBytes = arguments.getBytes(0, (int) arguments.length()); - ByteBuffer buf = ByteBuffer.wrap(argumentBytes); - argumentsFT = new FieldTable(buf,arguments.length()); - } - - queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); - + buf = null; } + + brh.binding(exchangeName, queueName, bindingKey, buf); } } finally @@ -501,44 +501,48 @@ public class DerbyMessageStore extends AbstractMessageStore } } + + public void close() throws Exception { + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); _closed.getAndSet(true); - - super.close(); } - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + public StoredMessage addMessage(StorableMessageMetaData metaData) { - - boolean localTx = getOrCreateTransaction(storeContext); - - Connection conn = getConnection(storeContext); - ConnectionWrapper wrapper = (ConnectionWrapper) storeContext.getPayload(); - - - if (_logger.isDebugEnabled()) + if(metaData.isPersistent()) { - _logger.debug("Message Id: " + messageId + " Removing"); + return new StoredDerbyMessage(_messageId.incrementAndGet(), metaData); } + else + { + return new StoredMemoryMessage(_messageId.incrementAndGet(), metaData); + } + } - // first we need to look up the header to get the chunk count - MessageMetaData mmd = getMessageMetaData(storeContext, messageId); + public StoredMessage getMessage(long messageNumber) + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeMessage(long messageId) + { + Connection conn = null; try { - PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_MESSAGE_META_DATA); + + + conn = newConnection(); + PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_META_DATA); stmt.setLong(1,messageId); - wrapper.setRequiresCommit(); int results = stmt.executeUpdate(); if (results == 0) { - if (localTx) - { - abortTran(storeContext); - } - throw new AMQException("Message metadata not found for message id " + messageId); + + throw new RuntimeException("Message metadata not found for message id " + messageId); } stmt.close(); @@ -551,29 +555,27 @@ public class DerbyMessageStore extends AbstractMessageStore stmt.setLong(1,messageId); results = stmt.executeUpdate(); - if(results != mmd.getContentChunkCount()) - { - if (localTx) - { - abortTran(storeContext); - } - throw new AMQException("Unexpected number of content chunks when deleting message. Expected " + mmd.getContentChunkCount() + " but found " + results); - } - if (localTx) - { - commitTran(storeContext); - } + conn.commit(); + conn.close(); } catch (SQLException e) { - if ((conn != null) && localTx) + if ((conn != null)) { - abortTran(storeContext); + try + { + conn.rollback(); + conn.close(); + } + catch (SQLException e1) + { + + } } - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + throw new RuntimeException("Error removing Message with id " + messageId + " to database: " + e, e); } } @@ -802,8 +804,14 @@ public class DerbyMessageStore extends AbstractMessageStore { stmt = conn.prepareStatement(INSERT_INTO_QUEUE); + String owner = queue.getPrincipalHolder() == null + ? null + : queue.getPrincipalHolder().getPrincipal() == null + ? null + : queue.getPrincipalHolder().getPrincipal().getName(); + stmt.setString(1, queue.getName().toString()); - stmt.setString(2, queue.getOwner() == null ? null : queue.getOwner().toString()); + stmt.setString(2, owner); stmt.execute(); @@ -873,29 +881,26 @@ public class DerbyMessageStore extends AbstractMessageStore } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public Transaction newTransaction() { - AMQShortString name = queue.getName(); + return new DerbyTransaction(); + } + + public void enqueueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException + { + String name = queue.getResourceName(); + + Connection conn = connWrapper.getConnection(); - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_QUEUE_ENTRY); - stmt.setString(1,name.toString()); + stmt.setString(1,name); stmt.setLong(2,messageId); stmt.executeUpdate(); connWrapper.requiresCommit(); - if(localTx) - { - commitTran(context); - } - - - if (_logger.isDebugEnabled()) { _logger.debug("Enqueuing message " + messageId + " on queue " + name + "[Connection" + conn + "]"); @@ -903,10 +908,6 @@ public class DerbyMessageStore extends AbstractMessageStore } catch (SQLException e) { - if(localTx) - { - abortTran(context); - } _logger.error("Failed to enqueue: " + e, e); throw new AMQException("Error writing enqueued message with id " + messageId + " for queue " + name + " to database", e); @@ -914,18 +915,18 @@ public class DerbyMessageStore extends AbstractMessageStore } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void dequeueMessage(ConnectionWrapper connWrapper, final TransactionLogResource queue, Long messageId) throws AMQException { - AMQShortString name = queue.getName(); + String name = queue.getResourceName(); + + + Connection conn = connWrapper.getConnection(); - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); try { PreparedStatement stmt = conn.prepareStatement(DELETE_FROM_QUEUE_ENTRY); - stmt.setString(1,name.toString()); + stmt.setString(1,name); stmt.setLong(2,messageId); int results = stmt.executeUpdate(); @@ -936,13 +937,6 @@ public class DerbyMessageStore extends AbstractMessageStore throw new AMQException("Unable to find message with id " + messageId + " on queue " + name); } - if(localTx) - { - commitTran(context); - } - - - if (_logger.isDebugEnabled()) { _logger.debug("Dequeuing message " + messageId + " on queue " + name );//+ "[Connection" + conn + "]"); @@ -950,10 +944,6 @@ public class DerbyMessageStore extends AbstractMessageStore } catch (SQLException e) { - if(localTx) - { - abortTran(context); - } _logger.error("Failed to dequeue: " + e, e); throw new AMQException("Error deleting enqueued message with id " + messageId + " for queue " + name + " from database", e); @@ -987,51 +977,20 @@ public class DerbyMessageStore extends AbstractMessageStore } } - public void beginTran(StoreContext context) throws AMQException - { - if (context.getPayload() != null) - { - throw new AMQException("Fatal internal error: transactional context is not empty at beginTran: " - + context.getPayload()); - } - else - { - try - { - Connection conn = newConnection(); - - context.setPayload(new ConnectionWrapper(conn)); - } - catch (SQLException e) - { - throw new AMQException("Error starting transaction: " + e, e); - } - } - } - - public void commitTran(StoreContext context) throws AMQException + public void commitTran(ConnectionWrapper connWrapper) throws AMQException { - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - - if (connWrapper == null) - { - throw new AMQException("Fatal internal error: transactional context is empty at commitTran"); - } try { Connection conn = connWrapper.getConnection(); - if(connWrapper.requiresCommit()) - { - conn.commit(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("commit tran completed"); - } + conn.commit(); + if (_logger.isDebugEnabled()) + { + _logger.debug("commit tran completed"); } + conn.close(); } catch (SQLException e) @@ -1040,14 +999,30 @@ public class DerbyMessageStore extends AbstractMessageStore } finally { - context.setPayload(null); + } } - public void abortTran(StoreContext context) throws AMQException + public StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws AMQException { - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + commitTran(connWrapper); + return new StoreFuture() + { + public boolean isComplete() + { + return true; + } + + public void waitForCompletion() + { + } + }; + + } + + public void abortTran(ConnectionWrapper connWrapper) throws AMQException + { if (connWrapper == null) { throw new AMQException("Fatal internal error: transactional context is empty at abortTran"); @@ -1072,272 +1047,261 @@ public class DerbyMessageStore extends AbstractMessageStore { throw new AMQException("Error aborting transaction: " + e, e); } - finally - { - context.setPayload(null); - } + } - public boolean inTran(StoreContext context) + public Long getNewMessageId() { - return context.getPayload() != null; + return _messageId.incrementAndGet(); } - public Long getNewMessageId() + + private void storeMetaData(Connection conn, long messageId, StorableMessageMetaData metaData) + throws SQLException { - return _messageId.getAndIncrement(); + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_META_DATA); + stmt.setLong(1,messageId); + + final int bodySize = 1 + metaData.getStorableSize(); + byte[] underlying = new byte[bodySize]; + underlying[0] = (byte) metaData.getType().ordinal(); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(underlying); + buf.position(1); + buf = buf.slice(); + + metaData.writeToBuffer(0, buf); + ByteArrayInputStream bis = new ByteArrayInputStream(underlying); + stmt.setBinaryStream(2,bis,underlying.length); + stmt.executeUpdate(); + } - public void storeContentBodyChunk(StoreContext context, - Long messageId, - int index, - ContentChunk contentBody, - boolean lastContentBody) throws AMQException + + + + private void recoverMessages(MessageStoreRecoveryHandler recoveryHandler) throws SQLException { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); + Connection conn = newConnection(); - try - { - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - stmt.setInt(2, index); - byte[] chunkData = new byte[contentBody.getSize()]; - contentBody.getData().duplicate().get(chunkData); - /* this would be the Java 6 way of doing things - Blob dataAsBlob = conn.createBlob(); - dataAsBlob.setBytes(1L, chunkData); - stmt.setBlob(3, dataAsBlob); - */ - ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); - stmt.setBinaryStream(3, bis, chunkData.length); - stmt.executeUpdate(); - connWrapper.requiresCommit(); + MessageStoreRecoveryHandler.StoredMessageRecoveryHandler messageHandler = recoveryHandler.begin(); - if(localTx) - { - commitTran(context); - } - } - catch (SQLException e) + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_ALL_FROM_META_DATA); + + long maxId = 0; + + while(rs.next()) { - if(localTx) + + long messageId = rs.getLong(1); + Blob dataAsBlob = rs.getBlob(2); + + if(messageId > maxId) { - abortTran(context); + maxId = messageId; } - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); + buf.position(1); + buf = buf.slice(); + MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; + StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); + StoredDerbyMessage message = new StoredDerbyMessage(messageId, metaData, false); + messageHandler.message(message); + + } + _messageId.set(maxId); + + messageHandler.completeMessageRecovery(); } - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData mmd) - throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - ConnectionWrapper connWrapper = (ConnectionWrapper) context.getPayload(); - try - { + private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) throws SQLException + { + Connection conn = newConnection(); - PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_META_DATA); - stmt.setLong(1,messageId); - stmt.setString(2, mmd.getMessagePublishInfo().getExchange().toString()); - stmt.setString(3, mmd.getMessagePublishInfo().getRoutingKey().toString()); - stmt.setShort(4, mmd.getMessagePublishInfo().isMandatory() ? (short) 1 : (short) 0); - stmt.setShort(5, mmd.getMessagePublishInfo().isImmediate() ? (short) 1 : (short) 0); - - ContentHeaderBody headerBody = mmd.getContentHeaderBody(); - final int bodySize = headerBody.getSize(); - byte[] underlying = new byte[bodySize]; - ByteBuffer buf = ByteBuffer.wrap(underlying); - headerBody.writePayload(buf); -/* - Blob dataAsBlob = conn.createBlob(); - dataAsBlob.setBytes(1L, underlying); - stmt.setBlob(6, dataAsBlob); -*/ - ByteArrayInputStream bis = new ByteArrayInputStream(underlying); - stmt.setBinaryStream(6,bis,underlying.length); + TransactionLogRecoveryHandler.QueueEntryRecoveryHandler queueEntryHandler = recoveryHandler.begin(this); - stmt.setInt(7, mmd.getContentChunkCount()); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); - stmt.executeUpdate(); - connWrapper.requiresCommit(); - if(localTx) - { - commitTran(context); - } - } - catch (SQLException e) + while(rs.next()) { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Error writing AMQMessage with id " + messageId + " to database: " + e, e); + String queueName = rs.getString(1); + long messageId = rs.getLong(2); + queueEntryHandler.queueEntry(queueName,messageId); } + + queueEntryHandler.completeQueueEntryRecovery(); + } - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException + StorableMessageMetaData getMetaData(long messageId) throws SQLException { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - + Connection conn = newConnection(); try { - - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_META_DATA); + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_META_DATA); stmt.setLong(1,messageId); ResultSet rs = stmt.executeQuery(); if(rs.next()) { - final AMQShortString exchange = new AMQShortString(rs.getString(1)); - final AMQShortString routingKey = rs.getString(2) == null ? null : new AMQShortString(rs.getString(2)); - final boolean mandatory = (rs.getShort(3) != (short)0); - final boolean immediate = (rs.getShort(4) != (short)0); - MessagePublishInfo info = new MessagePublishInfo() - { - public AMQShortString getExchange() - { - return exchange; - } + Blob dataAsBlob = rs.getBlob(1); - public void setExchange(AMQShortString exchange) - { + byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(dataAsBytes); + buf.position(1); + buf = buf.slice(); + MessageMetaDataType type = MessageMetaDataType.values()[dataAsBytes[0]]; + StorableMessageMetaData metaData = type.getFactory().createMetaData(buf); - } + return metaData; + } + else + { + throw new RuntimeException("Meta data not found for message with id " + messageId); + } - public boolean isImmediate() - { - return immediate; - } + } + finally + { + conn.close(); + } + } - public boolean isMandatory() - { - return mandatory; - } - public AMQShortString getRoutingKey() - { - return routingKey; - } - } ; + private void addContent(Connection conn, long messageId, int offset, ByteBuffer src) + { - Blob dataAsBlob = rs.getBlob(5); - byte[] dataAsBytes = dataAsBlob.getBytes(1,(int) dataAsBlob.length()); - ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); - ContentHeaderBody chb = ContentHeaderBody.createFromBuffer(buf, dataAsBytes.length); + try + { + final boolean newConnection = conn == null; - if(localTx) - { - commitTran(context); - } + if(newConnection) + { + conn = newConnection(); + } - return new MessageMetaData(info, chb, rs.getInt(6)); + src = src.slice(); - } - else + byte[] chunkData = new byte[src.limit()]; + src.duplicate().get(chunkData); + + PreparedStatement stmt = conn.prepareStatement(INSERT_INTO_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, offset); + stmt.setInt(3, offset+chunkData.length); + + + /* this would be the Java 6 way of doing things + Blob dataAsBlob = conn.createBlob(); + dataAsBlob.setBytes(1L, chunkData); + stmt.setBlob(3, dataAsBlob); + */ + ByteArrayInputStream bis = new ByteArrayInputStream(chunkData); + stmt.setBinaryStream(4, bis, chunkData.length); + stmt.executeUpdate(); + + if(newConnection) { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Metadata not found for message with id " + messageId); + conn.commit(); + conn.close(); } } catch (SQLException e) { - if(localTx) + if(conn != null) { - abortTran(context); + try + { + conn.close(); + } + catch (SQLException e1) + { + + } } - throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); } } - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - boolean localTx = getOrCreateTransaction(context); - Connection conn = getConnection(context); - - - try - { - PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); - stmt.setLong(1,messageId); - stmt.setInt(2, index); - ResultSet rs = stmt.executeQuery(); + public int getContent(long messageId, int offset, ByteBuffer dst) + { + Connection conn = null; - if(rs.next()) - { - Blob dataAsBlob = rs.getBlob(1); - final int size = (int) dataAsBlob.length(); - byte[] dataAsBytes = dataAsBlob.getBytes(1, size); - final ByteBuffer buf = ByteBuffer.wrap(dataAsBytes); + try + { + conn = newConnection(); - ContentChunk cb = new ContentChunk() - { + PreparedStatement stmt = conn.prepareStatement(SELECT_FROM_MESSAGE_CONTENT); + stmt.setLong(1,messageId); + stmt.setInt(2, offset); + stmt.setInt(3, offset+dst.remaining()); + ResultSet rs = stmt.executeQuery(); - public int getSize() - { - return size; - } + int written = 0; - public ByteBuffer getData() - { - return buf; - } + while(rs.next()) + { + int offsetInMessage = rs.getInt(1); + Blob dataAsBlob = rs.getBlob(2); - public void reduceToFit() - { + final int size = (int) dataAsBlob.length(); + byte[] dataAsBytes = dataAsBlob.getBytes(1, size); - } - }; + int posInArray = offset + written - offsetInMessage; + int count = size - posInArray; + if(count > dst.remaining()) + { + count = dst.remaining(); + } + dst.put(dataAsBytes,posInArray,count); + written+=count; - if(localTx) - { - commitTran(context); - } + if(dst.remaining() == 0) + { + break; + } + } - return cb; + conn.close(); + return written; - } - else - { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Message not found for message with id " + messageId); - } + } + catch (SQLException e) + { + if(conn != null) + { + try + { + conn.close(); } - catch (SQLException e) + catch (SQLException e1) { - if(localTx) - { - abortTran(context); - } - throw new AMQException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); } + } + + throw new RuntimeException("Error reading AMQMessage with id " + messageId + " from database: " + e, e); + } @@ -1348,173 +1312,158 @@ public class DerbyMessageStore extends AbstractMessageStore return true; } - private void checkNotClosed() throws MessageStoreClosedException - { - if (_closed.get()) - { - throw new MessageStoreClosedException(); - } - } - - private static final class ProcessAction + private synchronized void stateTransition(State requiredState, State newState) throws AMQException { - private final AMQQueue _queue; - private final StoreContext _context; - private final AMQMessage _message; - - public ProcessAction(AMQQueue queue, StoreContext context, AMQMessage message) - { - _queue = queue; - _context = context; - _message = message; - } - - public void process() throws AMQException + if (_state != requiredState) { - _queue.enqueue(_context, _message); + throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState + + "; currently in state: " + _state); } + _state = newState; } - private void deliverMessages(final StoreContext context, Map<AMQShortString, AMQQueue> queues) - throws SQLException, AMQException + private class DerbyTransaction implements Transaction { - Map<Long, AMQMessage> msgMap = new HashMap<Long,AMQMessage>(); - List<ProcessAction> actions = new ArrayList<ProcessAction>(); + private final ConnectionWrapper _connWrapper; - final boolean inLocaltran = inTran(context); - Connection conn = null; - try + private DerbyTransaction() { - if(inLocaltran) + try { - conn = getConnection(context); + _connWrapper = new ConnectionWrapper(newConnection()); } - else + catch (SQLException e) { - conn = newConnection(); + throw new RuntimeException(e); } + } - MessageHandleFactory messageHandleFactory = new MessageHandleFactory(); - long maxId = 1; + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, messageId); + } - TransactionalContext txnContext = new NonTransactionalContext(this, new StoreContext(), null, null); + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, messageId); - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(SELECT_FROM_QUEUE_ENTRY); + } - while (rs.next()) - { - AMQShortString queueName = new AMQShortString(rs.getString(1)); + public void commitTran() throws AMQException + { + DerbyMessageStore.this.commitTran(_connWrapper); + } - AMQQueue queue = queues.get(queueName); - if (queue == null) - { - queue = AMQQueueFactory.createAMQQueueImpl(queueName, false, null, false, _virtualHost, null); + public StoreFuture commitTranAsync() throws AMQException + { + return DerbyMessageStore.this.commitTranAsync(_connWrapper); + } - _virtualHost.getQueueRegistry().registerQueue(queue); - queues.put(queueName, queue); + public void abortTran() throws AMQException + { + DerbyMessageStore.this.abortTran(_connWrapper); + } + } - //Log Recovery Start - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1004(String.valueOf(queue.getName()), true)); - } + private class StoredDerbyMessage implements StoredMessage + { - long messageId = rs.getLong(2); - maxId = Math.max(maxId, messageId); - AMQMessage message = msgMap.get(messageId); + private final long _messageId; + private volatile WeakReference<StorableMessageMetaData> _metaDataRef; + private Connection _conn; - if(message != null) - { - message.incrementReference(); - } - else - { - message = new AMQMessage(messageId, this, messageHandleFactory, txnContext); - msgMap.put(messageId,message); - } + StoredDerbyMessage(long messageId, StorableMessageMetaData metaData) + { + this(messageId, metaData, true); + } - if (_logger.isDebugEnabled()) - { - _logger.debug("On recovery, delivering " + message.getMessageId() + " to " + queue.getName()); - } - Integer count = _queueRecoveries.get(queueName); - if (count == null) + StoredDerbyMessage(long messageId, + StorableMessageMetaData metaData, boolean persist) + { + try + { + _messageId = messageId; + + _metaDataRef = new WeakReference(metaData); + if(persist) { - count = 0; + _conn = newConnection(); + storeMetaData(_conn, messageId, metaData); } - - _queueRecoveries.put(queueName, ++count); - - actions.add(new ProcessAction(queue, context, message)); } - - for(ProcessAction action : actions) + catch (SQLException e) { - action.process(); + throw new RuntimeException(e); } - _messageId.set(maxId + 1); - } - catch (SQLException e) - { - _logger.error("Error: " + e, e); - throw e; } - finally + + public StorableMessageMetaData getMetaData() { - if (inLocaltran && conn != null) + StorableMessageMetaData metaData = _metaDataRef.get(); + if(metaData == null) { - conn.close(); + try + { + metaData = DerbyMessageStore.this.getMetaData(_messageId); + } + catch (SQLException e) + { + throw new RuntimeException(e); + } + _metaDataRef = new WeakReference(metaData); } + + return metaData; } - if (_logger.isInfoEnabled()) + public long getMessageNumber() { - _logger.info("Recovered message counts: " + _queueRecoveries); + return _messageId; } - for(Map.Entry<AMQShortString,Integer> entry : _queueRecoveries.entrySet()) + public void addContent(int offsetInMessage, java.nio.ByteBuffer src) { - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1005(entry.getValue(), String.valueOf(entry.getKey()))); - - CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1006(String.valueOf(entry.getKey()), true)); + DerbyMessageStore.this.addContent(_conn, _messageId, offsetInMessage, src); } - // Free the memory - _queueRecoveries = null; - - } - - private Connection getConnection(final StoreContext context) - { - return ((ConnectionWrapper)context.getPayload()).getConnection(); - } - - private boolean getOrCreateTransaction(StoreContext context) throws AMQException - { - - ConnectionWrapper tx = (ConnectionWrapper) context.getPayload(); - if (tx == null) + public int getContent(int offsetInMessage, java.nio.ByteBuffer dst) { - beginTran(context); - return true; + return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst); } - return false; - } - - private synchronized void stateTransition(State requiredState, State newState) throws AMQException - { - if (_state != requiredState) + public StoreFuture flushToStore() { - throw new AMQException("Cannot transition to the state: " + newState + "; need to be in state: " + requiredState - + "; currently in state: " + _state); + try + { + if(_conn != null) + { + _conn.commit(); + _conn.close(); + } + } + catch (SQLException e) + { + throw new RuntimeException(e); + } + finally + { + _conn = null; + } + return IMMEDIATE_FUTURE; } - _state = newState; + public void remove() + { + flushToStore(); + DerbyMessageStore.this.removeMessage(_messageId); + } } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java new file mode 100755 index 0000000000..cfbacd28c8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -0,0 +1,116 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.commons.configuration.Configuration; + +public interface DurableConfigurationStore +{ + + /** + * Called after instantiation in order to configure the message store. A particular implementation can define + * whatever parameters it wants. + * + * @param name The name to be used by this storem + * @param recoveryHandler Handler to be called as the store recovers on start up + * @param config The apache commons configuration object. + * + * @throws Exception If any error occurs that means the store is unable to configure itself. + */ + void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception; + /** + * Makes the specified exchange persistent. + * + * @param exchange The exchange to persist. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createExchange(Exchange exchange) throws AMQException; + + /** + * Removes the specified persistent exchange. + * + * @param exchange The exchange to remove. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void removeExchange(Exchange exchange) throws AMQException; + + /** + * Binds the specified queue to an exchange with a routing key. + * + * @param exchange The exchange to bind to. + * @param routingKey The routing key to bind by. + * @param queue The queue to bind. + * @param args Additional parameters. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Unbinds the specified from an exchange under a particular routing key. + * + * @param exchange The exchange to unbind from. + * @param routingKey The routing key to unbind. + * @param queue The queue to unbind. + * @param args Additonal parameters. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue) throws AMQException; + + /** + * Makes the specified queue persistent. + * + * @param queue The queue to store. + * + * @param arguments The additional arguments to the binding + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; + + /** + * Removes the specified queue from the persistent store. + * + * @param queue The queue to remove. + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void removeQueue(AMQQueue queue) throws AMQException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 87ec66030d..f43177bfc1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -20,21 +20,20 @@ */ package org.apache.qpid.server.store; -import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.messages.MessageStoreMessages; -import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.messages.ConfigStoreMessages; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.commons.configuration.Configuration; import java.util.ArrayList; import java.util.Collections; @@ -43,9 +42,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.nio.ByteBuffer; /** A simple message store that stores the messages in a threadsafe structure in memory. */ -public class MemoryMessageStore extends AbstractMessageStore +public class MemoryMessageStore implements MessageStore { private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); @@ -53,52 +53,74 @@ public class MemoryMessageStore extends AbstractMessageStore private static final String HASHTABLE_CAPACITY_CONFIG = "hashtable-capacity"; - protected ConcurrentMap<Long, MessageMetaData> _metaDataMap; - - protected ConcurrentMap<Long, List<ContentChunk>> _contentBodyMap; private final AtomicLong _messageId = new AtomicLong(1); private AtomicBoolean _closed = new AtomicBoolean(false); private LogSubject _logSubject; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + private static final Transaction IN_MEMORY_TRANSACTION = new Transaction() { - super.configure(virtualHost,base,config); + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + } - int hashtableCapacity = config.getStoreConfiguration().getInt(base + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); - _log.info("Using capacity " + hashtableCapacity + " for hash tables"); - _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>(hashtableCapacity); - _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>(hashtableCapacity); - } + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + } - public void close() throws Exception - { - _closed.getAndSet(true); - if (_metaDataMap != null) + public void commitTran() throws AMQException { - _metaDataMap.clear(); - _metaDataMap = null; } - if (_contentBodyMap != null) + + public StoreFuture commitTranAsync() throws AMQException + { + return IMMEDIATE_FUTURE; + } + + public void abortTran() throws AMQException { - _contentBodyMap.clear(); - _contentBodyMap = null; } - super.close(); + }; + + public void configureConfigStore(String name, ConfigurationRecoveryHandler handler, Configuration configuration, LogSubject logSubject) throws Exception + { + _logSubject = logSubject; + CurrentActor.get().message(_logSubject, ConfigStoreMessages.CFG_1001(this.getClass().getName())); + + } - public void removeMessage(StoreContext context, Long messageId) throws AMQException + public void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception { - checkNotClosed(); - if (_log.isDebugEnabled()) + if(_logSubject == null) { - _log.debug("Removing message with id " + messageId); + _logSubject = logSubject; } - _metaDataMap.remove(messageId); - _contentBodyMap.remove(messageId); + int hashtableCapacity = config.getInt(name + "." + HASHTABLE_CAPACITY_CONFIG, DEFAULT_HASHTABLE_CAPACITY); + _log.info("Using capacity " + hashtableCapacity + " for hash tables"); + CurrentActor.get().message(_logSubject, MessageStoreMessages.MST_1001(this.getClass().getName())); + } + + public void close() throws Exception + { + _closed.getAndSet(true); + CurrentActor.get().message(_logSubject,MessageStoreMessages.MST_1003()); + } + public StoredMessage addMessage(StorableMessageMetaData metaData) + { + final long id = _messageId.getAndIncrement(); + StoredMemoryMessage message = new StoredMemoryMessage(id, metaData); + + return message; + } + + public void createExchange(Exchange exchange) throws AMQException { @@ -135,35 +157,19 @@ public class MemoryMessageStore extends AbstractMessageStore // Not required to do anything } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception { - // Not required to do anything + //To change body of implemented methods use File | Settings | File Templates. } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public Transaction newTransaction() { - // Not required to do anything + return IN_MEMORY_TRANSACTION; } - public void beginTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void commitTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public void abortTran(StoreContext context) throws AMQException - { - // Not required to do anything - } - - public boolean inTran(StoreContext context) - { - return false; - } public List<AMQQueue> createQueues() throws AMQException { @@ -175,48 +181,6 @@ public class MemoryMessageStore extends AbstractMessageStore return _messageId.getAndIncrement(); } - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) - throws AMQException - { - checkNotClosed(); - List<ContentChunk> bodyList = _contentBodyMap.get(messageId); - - if (bodyList == null && lastContentBody) - { - _contentBodyMap.put(messageId, Collections.singletonList(contentBody)); - } - else - { - if (bodyList == null) - { - bodyList = new ArrayList<ContentChunk>(); - _contentBodyMap.put(messageId, bodyList); - } - - bodyList.add(index, contentBody); - } - } - - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) - throws AMQException - { - checkNotClosed(); - _metaDataMap.put(messageId, messageMetaData); - } - - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - checkNotClosed(); - return _metaDataMap.get(messageId); - } - - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - checkNotClosed(); - List<ContentChunk> bodyList = _contentBodyMap.get(messageId); - return bodyList.get(index); - } - public boolean isPersistent() { return false; @@ -229,4 +193,6 @@ public class MemoryMessageStore extends AbstractMessageStore throw new MessageStoreClosedException(); } } + + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java new file mode 100755 index 0000000000..428bb1e41b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageMetaDataType.java @@ -0,0 +1,41 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.message.MessageMetaData_0_10; + +import java.nio.ByteBuffer; + +public enum MessageMetaDataType +{ + META_DATA_0_8 { public Factory<MessageMetaData> getFactory() { return MessageMetaData.FACTORY; } }, + META_DATA_0_10 { public Factory<MessageMetaData_0_10> getFactory() { return MessageMetaData_0_10.FACTORY; } }; + + + public static interface Factory<M extends StorableMessageMetaData> + { + M createMetaData(ByteBuffer buf); + } + + abstract public Factory<? extends StorableMessageMetaData> getFactory(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index 5a1b54b298..e2fca2f9c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -20,53 +20,43 @@ */ package org.apache.qpid.server.store; +import org.apache.qpid.server.logging.LogSubject; import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - /** - * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages, queues - * and exchanges in a transactional manner. - * - * <p/>All message store, remove, enqueue and dequeue operations are carried out against a {@link StoreContext} which - * encapsulates the transactional context they are performed in. Many such operations can be carried out in a single - * transaction. + * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages. * - * <p/>The storage and removal of queues and exchanges, are not carried out in a transactional context. - * - * <p/><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities - * <tr><td> Accept transaction boundary demarcations: Begin, Commit, Abort. - * <tr><td> Store and remove queues. - * <tr><td> Store and remove exchanges. - * <tr><td> Store and remove messages. - * <tr><td> Bind and unbind queues to exchanges. - * <tr><td> Enqueue and dequeue messages to queues. - * <tr><td> Generate message identifiers. - * </table> */ -public interface MessageStore +public interface MessageStore extends DurableConfigurationStore, TransactionLog { + StoreFuture IMMEDIATE_FUTURE = new StoreFuture() + { + public boolean isComplete() + { + return true; + } + + public void waitForCompletion() + { + + } + }; + + /** * Called after instantiation in order to configure the message store. A particular implementation can define * whatever parameters it wants. * - * @param virtualHost The virtual host using by this store - * @param base The base element identifier from which all configuration items are relative. For example, if - * the base element is "store", the all elements used by concrete classes will be "store.foo" etc. - * @param hostConfig The apache commons configuration object. + * @param name The name to be used by this storem + * @param recoveryHandler Handler to be called as the store recovers on start up + * @param config The apache commons configuration object. * * @throws Exception If any error occurs that means the store is unable to configure itself. */ - void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration hostConfig) throws Exception; + void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception; /** * Called to close and cleanup any resources used by the message store. @@ -75,203 +65,16 @@ public interface MessageStore */ void close() throws Exception; - /** - * Removes the specified message from the store in the given transactional store context. - * - * @param storeContext The transactional context to remove the message in. - * @param messageId Identifies the message to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeMessage(StoreContext storeContext, Long messageId) throws AMQException; - - /** - * Makes the specified exchange persistent. - * - * @param exchange The exchange to persist. - * - * @throws AMQException If the operation fails for any reason. - */ - void createExchange(Exchange exchange) throws AMQException; - - /** - * Removes the specified persistent exchange. - * - * @param exchange The exchange to remove. - * - * @throws AMQException If the operation fails for any reason. - */ - void removeExchange(Exchange exchange) throws AMQException; - - /** - * Binds the specified queue to an exchange with a routing key. - * - * @param exchange The exchange to bind to. - * @param routingKey The routing key to bind by. - * @param queue The queue to bind. - * @param args Additional parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - - /** - * Unbinds the specified from an exchange under a particular routing key. - * - * @param exchange The exchange to unbind from. - * @param routingKey The routing key to unbind. - * @param queue The queue to unbind. - * @param args Additonal parameters. - * - * @throws AMQException If the operation fails for any reason. - */ - void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException; - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue) throws AMQException; + public <T extends StorableMessageMetaData> StoredMessage<T> addMessage(T metaData); - /** - * Makes the specified queue persistent. - * - * @param queue The queue to store. - * - * @param arguments The additional arguments to the binding - * @throws AMQException If the operation fails for any reason. - */ - void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException; - - /** - * Removes the specified queue from the persistent store. - * - * @param queue The queue to remove. - * @throws AMQException If the operation fails for any reason. - */ - void removeQueue(final AMQQueue queue) throws AMQException; - - /** - * Places a message onto a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to enqueue. - * @throws AMQException If the operation fails for any reason. - */ - void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Extracts a message from a specified queue, in a given transactional context. - * - * @param context The transactional context for the operation. - * @param queue The queue to place the message on. - * @param messageId The message to dequeue. - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException; - - /** - * Begins a transactional context. - * - * @param context The transactional context to begin. - * - * @throws AMQException If the operation fails for any reason. - */ - void beginTran(StoreContext context) throws AMQException; - - /** - * Commits all operations performed within a given transactional context. - * - * @param context The transactional context to commit all operations for. - * - * @throws AMQException If the operation fails for any reason. - */ - void commitTran(StoreContext context) throws AMQException; - - /** - * Abandons all operations performed within a given transactional context. - * - * @param context The transactional context to abandon. - * - * @throws AMQException If the operation fails for any reason. - */ - void abortTran(StoreContext context) throws AMQException; - - /** - * Tests a transactional context to see if it has been begun but not yet committed or aborted. - * - * @param context The transactional context to test. - * - * @return <tt>true</tt> if the transactional context is live, <tt>false</tt> otherwise. - */ - boolean inTran(StoreContext context); - - /** - * Return a valid, currently unused message id. - * - * @return A fresh message id. - */ - Long getNewMessageId(); - - /** - * Stores a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param index The index of the data chunk. - * @param contentBody The content of the data chunk. - * @param lastContentBody Flag to indicate that this is the last such chunk for the message. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, - boolean lastContentBody) throws AMQException; - - /** - * Stores message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to store the data for. - * @param messageMetaData The message meta data to store. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException; - - /** - * Retrieves message meta-data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the meta-data for. - * - * @return The message meta data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException; - - /** - * Retrieves a chunk of message data. - * - * @param context The transactional context for the operation. - * @param messageId The message to get the data chunk for. - * @param index The offset index of the data chunk within the message. - * - * @return A chunk of message data. - * - * @throws AMQException If the operation fails for any reason, or if the specified message does not exist. - */ - ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException; /** * Is this store capable of persisting the data - * + * * @return true if this store is capable of persisting data */ boolean isPersistent(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java new file mode 100755 index 0000000000..ba65b8e1ec --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStoreRecoveryHandler.java @@ -0,0 +1,33 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +public interface MessageStoreRecoveryHandler +{ + StoredMessageRecoveryHandler begin(); + + public static interface StoredMessageRecoveryHandler + { + void message(StoredMessage message); + + void completeMessageRecovery(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java new file mode 100755 index 0000000000..12d2a6a6c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java @@ -0,0 +1,36 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; + +public interface StorableMessageMetaData +{ + MessageMetaDataType getType(); + + int getStorableSize(); + + int writeToBuffer(int offsetInMetaData, ByteBuffer dest); + + int getContentSize(); + + boolean isPersistent(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java index fdb56a1a55..88cc68bc71 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoreContext.java @@ -35,6 +35,7 @@ public class StoreContext private String _name; private Object _payload; + public StoreContext() { _name = "StoreContext"; @@ -68,4 +69,5 @@ public class StoreContext { return "<_name = " + _name + ", _payload = " + _payload + ">"; } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java new file mode 100755 index 0000000000..867fb4f9c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java @@ -0,0 +1,80 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; + +public class StoredMemoryMessage implements StoredMessage +{ + private final long _messageNumber; + private final ByteBuffer _content; + private final StorableMessageMetaData _metaData; + + StoredMemoryMessage(long messageNumber, StorableMessageMetaData metaData) + { + _messageNumber = messageNumber; + _metaData = metaData; + _content = ByteBuffer.allocate(metaData.getContentSize()); + + } + + public long getMessageNumber() + { + return _messageNumber; + } + + public void addContent(int offsetInMessage, ByteBuffer src) + { + src = src.duplicate(); + ByteBuffer dst = _content.duplicate(); + dst.position(offsetInMessage); + dst.put(src); + } + + public int getContent(int offset, ByteBuffer dst) + { + ByteBuffer src = _content.duplicate(); + src.position(offset); + src = src.slice(); + if(dst.remaining() < src.limit()) + { + src.limit(dst.remaining()); + } + dst.put(src); + return src.limit(); + } + + public TransactionLog.StoreFuture flushToStore() + { + return MessageStore.IMMEDIATE_FUTURE; + } + + + public StorableMessageMetaData getMetaData() + { + return _metaData; + } + + public void remove() + { + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java new file mode 100755 index 0000000000..0bc45c6718 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java @@ -0,0 +1,38 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +import java.nio.ByteBuffer; + +public interface StoredMessage<M extends StorableMessageMetaData> +{ + M getMetaData(); + + public long getMessageNumber(); + + void addContent(int offsetInMessage, ByteBuffer src); + + int getContent(int offsetInMessage, ByteBuffer dst); + + TransactionLog.StoreFuture flushToStore(); + + void remove(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java new file mode 100755 index 0000000000..e6a33e23d6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java @@ -0,0 +1,92 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.AMQException; +import org.apache.commons.configuration.Configuration; + +public interface TransactionLog +{ + + public static interface Transaction + { + /** + * Places a message onto a specified queue, in a given transactional context. + * + * @param queue The queue to place the message on. + * @param messageId The message to enqueue. + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException; + + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param queue The queue to place the message on. + * @param messageId The message to dequeue. + * @throws org.apache.qpid.AMQException If the operation fails for any reason, or if the specified message does not exist. + */ + void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException; + + + /** + * Commits all operations performed within a given transactional context. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void commitTran() throws AMQException; + + /** + * Commits all operations performed within a given transactional context. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + StoreFuture commitTranAsync() throws AMQException; + + /** + * Abandons all operations performed within a given transactional context. + * + * @throws org.apache.qpid.AMQException If the operation fails for any reason. + */ + void abortTran() throws AMQException; + + + + } + + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception; + + Transaction newTransaction(); + + + + public static interface StoreFuture + { + boolean isComplete(); + + void waitForCompletion(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java new file mode 100755 index 0000000000..7781c52df3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java @@ -0,0 +1,33 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +public interface TransactionLogRecoveryHandler +{ + QueueEntryRecoveryHandler begin(TransactionLog log); + + public static interface QueueEntryRecoveryHandler + { + void queueEntry(String queuename, long messageId); + + void completeQueueEntryRecovery(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java new file mode 100755 index 0000000000..0d81dd151d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogResource.java @@ -0,0 +1,26 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.store; + +public interface TransactionLogResource +{ + public String getResourceName(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java new file mode 100755 index 0000000000..b49b12fb79 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java @@ -0,0 +1,93 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.log4j.Logger; + + +class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener +{ + private static final Logger _logger = Logger.getLogger(ExplicitAcceptDispositionChangeListener.class); + + + private final QueueEntry _entry; + private final Subscription_0_10 _sub; + + public ExplicitAcceptDispositionChangeListener(QueueEntry entry, Subscription_0_10 subscription_0_10) + { + _entry = entry; + _sub = subscription_0_10; + } + + public void onAccept() + { + final Subscription_0_10 subscription = getSubscription(); + if(subscription != null && _entry.isAcquiredBy(_sub)) + { + subscription.getSession().acknowledge(subscription, _entry); + } + else + { + _logger.warn("MessageAccept received for message which has not been acquired (likely client error)"); + } + + } + + public void onRelease() + { + final Subscription_0_10 subscription = getSubscription(); + if(subscription != null && _entry.isAcquiredBy(_sub)) + { + subscription.release(_entry); + } + else + { + _logger.warn("MessageRelease received for message which has not been acquired (likely client error)"); + } + } + + public void onReject() + { + final Subscription_0_10 subscription = getSubscription(); + if(subscription != null && _entry.isAcquiredBy(_sub)) + { + subscription.reject(_entry); + } + else + { + _logger.warn("MessageReject received for message which has not been acquired (likely client error)"); + } + + } + + public boolean acquire() + { + return _entry.acquire(getSubscription()); + } + + + private Subscription_0_10 getSubscription() + { + return _sub; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java new file mode 100755 index 0000000000..b5bb2014b5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java @@ -0,0 +1,86 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.log4j.Logger; + +class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener +{ + private static final Logger _logger = Logger.getLogger(ImplicitAcceptDispositionChangeListener.class); + + + private final QueueEntry _entry; + private Subscription_0_10 _sub; + + public ImplicitAcceptDispositionChangeListener(QueueEntry entry, Subscription_0_10 subscription_0_10) + { + _entry = entry; + _sub = subscription_0_10; + } + + public void onAccept() + { + _logger.warn("MessageAccept received for message which is using NONE as the accept mode (likely client error)"); + } + + public void onRelease() + { + if(_entry.isAcquiredBy(_sub)) + { + getSubscription().release(_entry); + } + else + { + _logger.warn("MessageRelease received for message which has not been acquired (likely client error)"); + } + } + + public void onReject() + { + if(_entry.isAcquiredBy(_sub)) + { + getSubscription().reject(_entry); + } + else + { + _logger.warn("MessageReject received for message which has not been acquired (likely client error)"); + } + + } + + public boolean acquire() + { + boolean acquired = _entry.acquire(getSubscription()); + //TODO - why acknowledge here??? seems bizarre... + // getSubscription().getSession().acknowledge(getSubscription(), _entry); + return acquired; + + } + + public Subscription_0_10 getSubscription() + { + return _sub; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java new file mode 100755 index 0000000000..8a2a370236 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageAcceptCompletionListener.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.transport.Method; + +public class MessageAcceptCompletionListener implements Method.CompletionListener +{ + private final Subscription_0_10 _sub; + private final QueueEntry _entry; + private final ServerSession _session; + private boolean _restoreCredit; + + public MessageAcceptCompletionListener(Subscription_0_10 sub, ServerSession session, QueueEntry entry, boolean restoreCredit) + { + super(); + _sub = sub; + _entry = entry; + _session = session; + _restoreCredit = restoreCredit; + } + + public void onComplete(Method method) + { + if(_restoreCredit) + { + _sub.restoreCredit(_entry); + } + if(_entry.isAcquiredBy(_sub)) + { + _session.acknowledge(_sub, _entry); + } + + _session.removeDispositionListener(method); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index c9042325bf..4db9c305b2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -46,10 +46,12 @@ public interface Subscription AMQQueue getQueue(); QueueEntry.SubscriptionAcquiredState getOwningState(); + QueueEntry.SubscriptionAssignedState getAssignedState(); + void setQueue(AMQQueue queue, boolean exclusive); - AMQChannel getChannel(); + void setNoLocal(boolean noLocal); AMQShortString getConsumerTag(); @@ -63,23 +65,24 @@ public interface Subscription boolean isClosed(); - boolean isBrowser(); + boolean acquires(); - void close(); + boolean seesRequeues(); - boolean filtersMessages(); + void close(); void send(QueueEntry msg) throws AMQException; - void queueDeleted(AMQQueue queue); + void queueDeleted(AMQQueue queue); boolean wouldSuspend(QueueEntry msg); void getSendLock(); + void releaseSendLock(); - void resend(final QueueEntry entry) throws AMQException; + void onDequeue(final QueueEntry queueEntry); void restoreCredit(final QueueEntry queueEntry); @@ -87,13 +90,17 @@ public interface Subscription public State getState(); - QueueEntry getLastSeenEntry(); + AMQQueue.Context getQueueContext(); - boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue); + void setQueueContext(AMQQueue.Context queueContext); boolean isActive(); + void confirmAutoClose(); + + public void set(String key, Object value); + public Object get(String key); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 2893e916cc..bb2e5ae918 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -25,6 +25,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; @@ -33,6 +35,8 @@ import org.apache.qpid.common.ClientProperties; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.SubscriptionActor; import org.apache.qpid.server.logging.messages.SubscriptionMessages; @@ -45,7 +49,6 @@ import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.store.StoreContext; /** * Encapsulation of a supscription to a queue. <p/> Ties together the protocol session of a subscriber, the consumer tag @@ -65,11 +68,16 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE); - private final AtomicReference<QueueEntry> _queueContext = new AtomicReference<QueueEntry>(null); + private AMQQueue.Context _queueContext; + private final ClientDeliveryMethod _deliveryMethod; private final RecordDeliveryMethod _recordMethod; - private QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this); + + private final Map<String, Object> _properties = new ConcurrentHashMap<String, Object>(); + private final Lock _stateChangeLock; private static final AtomicLong idGenerator = new AtomicLong(0); @@ -78,6 +86,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private LogSubject _logSubject; private LogActor _logActor; + static final class BrowserSubscription extends SubscriptionImpl { public BrowserSubscription(AMQChannel channel, AMQProtocolSession protocolSession, @@ -153,38 +162,28 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage @Override public void send(QueueEntry entry) throws AMQException { + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - StoreContext storeContext = getChannel().getStoreContext(); - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - entry.dequeue(storeContext); + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. + entry.dequeue(); - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); - sendToClient(entry, deliveryTag); + sendToClient(entry, deliveryTag); - } - entry.dispose(storeContext); } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? + entry.dispose(); + - entry.setDeliveredToSubscription(); - } } @Override @@ -225,39 +224,30 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public void send(QueueEntry entry) throws AMQException { - try - { // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. + // if we do not need to wait for client acknowledgements + // we can decrement the reference count immediately. - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. + // By doing this _before_ the send we ensure that it + // doesn't get sent if it can't be dequeued, preventing + // duplicate delivery on recovery. - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. + // The send may of course still fail, in which case, as + // the message is unacked, it will be lost. - synchronized (getChannel()) - { - long deliveryTag = getChannel().getNextDeliveryTag(); + synchronized (getChannel()) + { + long deliveryTag = getChannel().getNextDeliveryTag(); - recordMessageDelivery(entry, deliveryTag); - sendToClient(entry, deliveryTag); + recordMessageDelivery(entry, deliveryTag); + sendToClient(entry, deliveryTag); - } - } - finally - { - //Only set delivered if it actually was writen successfully.. - // using a try->finally would set it even if an error occured. - // Is this what we want? - - entry.setDeliveredToSubscription(); } } + } @@ -268,7 +258,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private final AMQShortString _consumerTag; - private final boolean _noLocal; + private boolean _noLocal; private final FlowCreditManager _creditManager; @@ -423,43 +413,35 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public boolean hasInterest(QueueEntry entry) { + + + + //check that the message hasn't been rejected if (entry.isRejectedBy(this)) { if (_logger.isDebugEnabled()) { - _logger.debug("Subscription:" + debugIdentity() + " rejected message:" + entry.debugIdentity()); + _logger.debug("Subscription:" + this + " rejected message:" + entry); } // return false; } if (_noLocal) { - //todo - client id should be recoreded so we don't have to handle + + AMQMessage message = (AMQMessage) entry.getMessage(); + + //todo - client id should be recorded so we don't have to handle // the case where this is null. - final Object publisherId = entry.getMessage().getPublisherClientInstance(); + final Object publisher = message.getPublisherIdentifier(); // We don't want local messages so check to see if message is one we sent - Object localInstance; + Object localInstance = getProtocolSession(); - if (publisherId != null && (getProtocolSession().getClientProperties() != null) && - (localInstance = getProtocolSession().getClientProperties().getObject(CLIENT_PROPERTIES_INSTANCE)) != null) + if(publisher.equals(localInstance)) { - if(publisherId.equals(localInstance)) - { - return false; - } - } - else - { - - localInstance = getProtocolSession().getClientIdentifier(); - - //todo - client id should be recoreded so we don't have to do the null check - if (localInstance != null && localInstance.equals(entry.getMessage().getPublisherIdentifier())) - { - return false; - } + return false; } @@ -468,7 +450,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage if (_logger.isDebugEnabled()) { - _logger.debug("(" + debugIdentity() + ") checking filters for message (" + entry.debugIdentity()); + _logger.debug("(" + this + ") checking filters for message (" + entry); } return checkFilters(entry); @@ -483,7 +465,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private boolean checkFilters(QueueEntry msg) { - return (_filters == null) || _filters.allAllow(msg.getMessage()); + return (_filters == null) || _filters.allAllow(msg); } public boolean isAutoClose() @@ -550,11 +532,6 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _stateChangeLock.unlock(); } - public void resend(final QueueEntry entry) throws AMQException - { - _queue.resend(entry, this); - } - public AMQChannel getChannel() { return _channel; @@ -585,12 +562,18 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _queue; } + public void onDequeue(final QueueEntry queueEntry) + { + restoreCredit(queueEntry); + } + public void restoreCredit(final QueueEntry queueEntry) { - _creditManager.addCredit(1, queueEntry.getSize()); + _creditManager.restoreCredit(1, queueEntry.getSize()); } + public void creditStateChanged(boolean hasCredit) { @@ -628,22 +611,14 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } - public QueueEntry getLastSeenEntry() + public AMQQueue.Context getQueueContext() { - QueueEntry entry = _queueContext.get(); - - if(_logger.isDebugEnabled()) - { - _logger.debug(_logActor + ": lastSeenEntry: " + (entry == null ? "null" : entry.debugIdentity())); - } - - return entry; + return _queueContext; } - public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newvalue) + public void setQueueContext(AMQQueue.Context context) { - _logger.debug(debugIdentity() + " Setting Last Seen To:" + (newvalue == null ? "nullNV" : newvalue.debugIdentity())); - return _queueContext.compareAndSet(expected,newvalue); + _queueContext = context; } @@ -670,4 +645,43 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _owningState; } + public QueueEntry.SubscriptionAssignedState getAssignedState() + { + return _assignedState; + } + + + public void confirmAutoClose() + { + ProtocolOutputConverter converter = getChannel().getProtocolSession().getProtocolOutputConverter(); + converter.confirmConsumerAutoClose(getChannel().getChannelId(), getConsumerTag()); + } + + public boolean acquires() + { + return !isBrowser(); + } + + public boolean seesRequeues() + { + return !isBrowser(); + } + + public void set(String key, Object value) + { + _properties.put(key, value); + } + + public Object get(String key) + { + return _properties.get(key); + } + + + public void setNoLocal(boolean noLocal) + { + _noLocal = noLocal; + } + + abstract boolean isBrowser(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java new file mode 100644 index 0000000000..fb0a5cf2c7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -0,0 +1,658 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.CreditCreditManager; +import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.flow.FlowCreditManager_0_10; +import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.SubscriptionActor; +import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ContentHeaderProperties; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.AMQTypedValue; +import org.apache.qpid.AMQException; +import org.apache.qpid.transport.*; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.nio.ByteBuffer; + +public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCreditManagerListener +{ + + private static final AtomicLong idGenerator = new AtomicLong(0); + // Create a simple ID that increments for ever new Subscription + private final long _subscriptionID = idGenerator.getAndIncrement(); + + private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this); + + private final Lock _stateChangeLock = new ReentrantLock(); + + private final AtomicReference<State> _state = new AtomicReference<State>(State.ACTIVE); + private AMQQueue.Context _queueContext; + private final AtomicBoolean _deleted = new AtomicBoolean(false); + + + private FlowCreditManager_0_10 _creditManager; + + + private StateListener _stateListener = new StateListener() + { + + public void stateChange(Subscription sub, State oldState, State newState) + { + + } + }; + private AMQQueue _queue; + private final String _destination; + private boolean _noLocal; + private final FilterManager _filters; + private final MessageAcceptMode _acceptMode; + private final MessageAcquireMode _acquireMode; + private MessageFlowMode _flowMode; + private final ServerSession _session; + private AtomicBoolean _stopped = new AtomicBoolean(true); + private ConcurrentHashMap<Integer, QueueEntry> _sentMap = new ConcurrentHashMap<Integer, QueueEntry>(); + private static final Struct[] EMPTY_STRUCT_ARRAY = new Struct[0]; + + private LogSubject _logSubject; + private LogActor _logActor; + private Map<String, Object> _properties = new ConcurrentHashMap<String, Object>(); + + + public Subscription_0_10(ServerSession session, String destination, MessageAcceptMode acceptMode, + MessageAcquireMode acquireMode, + MessageFlowMode flowMode, + FlowCreditManager_0_10 creditManager, + FilterManager filters) + { + _session = session; + _destination = destination; + _acceptMode = acceptMode; + _acquireMode = acquireMode; + _creditManager = creditManager; + _flowMode = flowMode; + _filters = filters; + _creditManager.addStateListener(this); + _state.set(_creditManager.hasCredit() ? State.ACTIVE : State.SUSPENDED); + + + } + + public void setNoLocal(boolean noLocal) + { + _noLocal = noLocal; + } + + public AMQQueue getQueue() + { + return _queue; + } + + public QueueEntry.SubscriptionAcquiredState getOwningState() + { + return _owningState; + } + + public QueueEntry.SubscriptionAssignedState getAssignedState() + { + return _assignedState; + } + + public void setQueue(AMQQueue queue, boolean exclusive) + { + if(getQueue() != null) + { + throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); + } + _queue = queue; + _logSubject = new SubscriptionLogSubject(this); + _logActor = new SubscriptionActor(CurrentActor.get().getRootMessageLogger(), this); + + } + + public AMQShortString getConsumerTag() + { + return new AMQShortString(_destination); + } + + public boolean isSuspended() + { + return !isActive() || _deleted.get(); // TODO check for Session suspension + } + + public boolean hasInterest(QueueEntry entry) + { + + + + //check that the message hasn't been rejected + if (entry.isRejectedBy(this)) + { + + return false; + } + + + + if (_noLocal + && (entry.getMessage() instanceof MessageTransferMessage) + && ((MessageTransferMessage)entry.getMessage()).getSession() == _session) + { + return false; + } + + + return checkFilters(entry); + + + } + + private boolean checkFilters(QueueEntry entry) + { + return (_filters == null) || _filters.allAllow(entry); + } + + public boolean isAutoClose() + { + // no such thing in 0-10 + return false; + } + + public boolean isClosed() + { + return getState() == State.CLOSED; + } + + public boolean isBrowser() + { + return _acquireMode == MessageAcquireMode.NOT_ACQUIRED; + } + + public boolean seesRequeues() + { + return _acquireMode != MessageAcquireMode.NOT_ACQUIRED || _acceptMode == MessageAcceptMode.EXPLICIT; + } + + public void close() + { + boolean closed = false; + State state = getState(); + + _stateChangeLock.lock(); + try + { + while(!closed && state != State.CLOSED) + { + closed = _state.compareAndSet(state, State.CLOSED); + if(!closed) + { + state = getState(); + } + else + { + _stateListener.stateChange(this,state, State.CLOSED); + } + } + _creditManager.removeListener(this); + } + finally + { + _stateChangeLock.unlock(); + } + + + + } + + public void creditStateChanged(boolean hasCredit) + { + + if(hasCredit) + { + if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) + { + _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + } + else + { + // this is a hack to get round the issue of increasing bytes credit + _stateListener.stateChange(this, State.ACTIVE, State.ACTIVE); + } + } + else + { + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + } + } + + + private class AddMessageDispositionListnerAction implements Runnable + { + public MessageTransfer _xfr; + public ServerSession.MessageDispositionChangeListener _action; + + public void run() + { + _session.onMessageDispositionChange(_xfr, _action); + } + } + + private final AddMessageDispositionListnerAction _postIdSettingAction = new AddMessageDispositionListnerAction(); + + public void send(final QueueEntry entry) throws AMQException + { + ServerMessage serverMsg = entry.getMessage(); + + + MessageTransfer xfr; + + if(serverMsg instanceof MessageTransferMessage) + { + + MessageTransferMessage msg = (MessageTransferMessage) serverMsg; + + + Struct[] headers; + if(msg.getHeader() == null) + { + headers = EMPTY_STRUCT_ARRAY; + } + else + { + headers = msg.getHeader().getStructs(); + } + + ArrayList<Struct> newHeaders = new ArrayList<Struct>(headers.length); + DeliveryProperties origDeliveryProps = null; + for(Struct header : headers) + { + if(header instanceof DeliveryProperties) + { + origDeliveryProps = (DeliveryProperties) header; + } + else + { + newHeaders.add(header); + } + } + + DeliveryProperties deliveryProps = new DeliveryProperties(); + if(origDeliveryProps != null) + { + if(origDeliveryProps.hasDeliveryMode()) + { + deliveryProps.setDeliveryMode(origDeliveryProps.getDeliveryMode()); + } + if(origDeliveryProps.hasExchange()) + { + deliveryProps.setExchange(origDeliveryProps.getExchange()); + } + if(origDeliveryProps.hasExpiration()) + { + deliveryProps.setExpiration(origDeliveryProps.getExpiration()); + } + if(origDeliveryProps.hasPriority()) + { + deliveryProps.setPriority(origDeliveryProps.getPriority()); + } + if(origDeliveryProps.hasRoutingKey()) + { + deliveryProps.setRoutingKey(origDeliveryProps.getRoutingKey()); + } + + } + + deliveryProps.setRedelivered(entry.isRedelivered()); + + newHeaders.add(deliveryProps); + Header header = new Header(newHeaders); + + xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody()); + } + else + { + AMQMessage message_0_8 = (AMQMessage) serverMsg; + DeliveryProperties deliveryProps = new DeliveryProperties(); + MessageProperties messageProps = new MessageProperties(); + + int size = (int) message_0_8.getSize(); + ByteBuffer body = ByteBuffer.allocate(size); + message_0_8.getContent(body, 0); + body.flip(); + + Struct[] headers = new Struct[] { deliveryProps, messageProps }; + + BasicContentHeaderProperties properties = + (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().properties; + final AMQShortString exchange = message_0_8.getMessagePublishInfo().getExchange(); + if(exchange != null) + { + deliveryProps.setExchange(exchange.toString()); + } + deliveryProps.setExpiration(message_0_8.getExpiration()); + deliveryProps.setImmediate(message_0_8.isImmediate()); + deliveryProps.setPriority(MessageDeliveryPriority.get(properties.getPriority())); + deliveryProps.setRedelivered(entry.isRedelivered()); + deliveryProps.setRoutingKey(message_0_8.getRoutingKey()); + deliveryProps.setTimestamp(properties.getTimestamp()); + + messageProps.setContentEncoding(properties.getEncodingAsString()); + messageProps.setContentLength(size); + if(properties.getAppId() != null) + { + messageProps.setAppId(properties.getAppId().getBytes()); + } + messageProps.setContentType(properties.getContentTypeAsString()); + if(properties.getCorrelationId() != null) + { + messageProps.setCorrelationId(properties.getCorrelationId().getBytes()); + } + + // TODO - ReplyTo + + if(properties.getUserId() != null) + { + messageProps.setUserId(properties.getUserId().getBytes()); + } + + final Map<String, Object> appHeaders = new HashMap<String, Object>(); + + properties.getHeaders().processOverElements( + new FieldTable.FieldTableElementProcessor() + { + + public boolean processElement(String propertyName, AMQTypedValue value) + { + Object val = value.getValue(); + if(val instanceof AMQShortString) + { + val = val.toString(); + } + appHeaders.put(propertyName, val); + return true; + } + + public Object getResult() + { + return appHeaders; + } + }); + + + messageProps.setApplicationHeaders(appHeaders); + + Header header = new Header(headers); + xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); + } + + if(_acceptMode == MessageAcceptMode.NONE) + { + xfr.setCompletionListener(new MessageAcceptCompletionListener(this, _session, entry, _flowMode == MessageFlowMode.WINDOW)); + } + else if(_flowMode == MessageFlowMode.WINDOW) + { + xfr.setCompletionListener(new Method.CompletionListener() + { + public void onComplete(Method method) + { + restoreCredit(entry); + } + }); + } + + + _postIdSettingAction._xfr = xfr; + if(_acceptMode == MessageAcceptMode.EXPLICIT) + { + _postIdSettingAction._action = new ExplicitAcceptDispositionChangeListener(entry, this); + } + else + { + _postIdSettingAction._action = new ImplicitAcceptDispositionChangeListener(entry, this); + } + + _session.sendMessage(xfr, _postIdSettingAction); + + } + + void reject(QueueEntry entry) + { + entry.setRedelivered(); + entry.routeToAlternate(); + + } + + void release(QueueEntry entry) + { + entry.setRedelivered(); + entry.release(); + } + + public void queueDeleted(AMQQueue queue) + { + _deleted.set(true); + } + + public boolean wouldSuspend(QueueEntry msg) + { + return !_creditManager.useCreditForMessage(msg.getMessage()); + } + + public void getSendLock() + { + _stateChangeLock.lock(); + } + + public void releaseSendLock() + { + _stateChangeLock.unlock(); + } + + public void restoreCredit(QueueEntry queueEntry) + { + _creditManager.restoreCredit(1, queueEntry.getSize()); + } + + public void onDequeue(QueueEntry queueEntry) + { + + } + + public void setStateListener(StateListener listener) + { + _stateListener = listener; + } + + public State getState() + { + return _state.get(); + } + + public AMQQueue.Context getQueueContext() + { + return _queueContext; + } + + public void setQueueContext(AMQQueue.Context queueContext) + { + _queueContext = queueContext; + } + + public boolean isActive() + { + return getState() == State.ACTIVE; + } + + public void confirmAutoClose() + { + //No such thing in 0-10 + } + + public void set(String key, Object value) + { + _properties.put(key, value); + } + + public Object get(String key) + { + return _properties.get(key); + } + + + public FlowCreditManager_0_10 getCreditManager() + { + return _creditManager; + } + + + public void stop() + { + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + _stopped.set(true); + FlowCreditManager_0_10 creditManager = getCreditManager(); + creditManager.clearCredit(); + } + + public void addCredit(MessageCreditUnit unit, long value) + { + FlowCreditManager_0_10 creditManager = getCreditManager(); + + switch (unit) + { + case MESSAGE: + + creditManager.addCredit(value, 0L); + break; + case BYTE: + creditManager.addCredit(0l, value); + break; + } + + _stopped.set(false); + + if(creditManager.hasCredit()) + { + if(_state.compareAndSet(State.SUSPENDED, State.ACTIVE)) + { + _stateListener.stateChange(this, State.SUSPENDED, State.ACTIVE); + } + } + + } + + public void setFlowMode(MessageFlowMode flowMode) + { + + + _creditManager.removeListener(this); + + switch(flowMode) + { + case CREDIT: + _creditManager = new CreditCreditManager(0l,0l); + break; + case WINDOW: + _creditManager = new WindowCreditManager(0l,0l); + break; + default: + throw new RuntimeException("Unknown message flow mode: " + flowMode); + } + _flowMode = flowMode; + if(_state.compareAndSet(State.ACTIVE, State.SUSPENDED)) + { + _stateListener.stateChange(this, State.ACTIVE, State.SUSPENDED); + } + + _creditManager.addStateListener(this); + + } + + public boolean isStopped() + { + return _stopped.get(); + } + + public boolean acquires() + { + return _acquireMode == MessageAcquireMode.PRE_ACQUIRED; + } + + public void acknowledge(QueueEntry entry) + { + // TODO Fix Store Context / cleanup + if(entry.isAcquiredBy(this)) + { + entry.discard(); + } + } + + public void flush() throws AMQException + { + _queue.flushSubscription(this); + stop(); + } + + public long getSubscriptionID() + { + return _subscriptionID; + } + + public LogActor getLogActor() + { + return _logActor; + } + + ServerSession getSession() + { + return _session; + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java new file mode 100644 index 0000000000..2a8b99ddac --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.Method; +import org.apache.qpid.server.virtualhost.VirtualHost; + +public class ServerConnection extends Connection +{ + @Override + protected void invoke(Method method) + { + super.invoke(method); + } + + @Override + protected void setState(State state) + { + super.setState(state); + } + + @Override + public ServerConnectionDelegate getConnectionDelegate() + { + return (ServerConnectionDelegate) super.getConnectionDelegate(); + } + + public void setConnectionDelegate(ServerConnectionDelegate delegate) + { + super.setConnectionDelegate(delegate); + } + + private VirtualHost _virtualHost; + + + public VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public void setVirtualHost(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java new file mode 100644 index 0000000000..cfc5bb3a72 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -0,0 +1,120 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.*; + +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import java.util.*; + + +public class ServerConnectionDelegate extends ServerDelegate +{ + + private String _localFQDN; + private final IApplicationRegistry _appRegistry; + + + public ServerConnectionDelegate(IApplicationRegistry appRegistry, + String localFQDN) + { + this(Collections.EMPTY_MAP, Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); + } + + + public ServerConnectionDelegate(Map<String, Object> properties, + List<Object> locales, + IApplicationRegistry appRegistry, + String localFQDN) + { + super(properties, parseToList(appRegistry.getAuthenticationManager().getMechanisms()), locales); + _appRegistry = appRegistry; + _localFQDN = localFQDN; + } + + private static List<Object> parseToList(String mechanisms) + { + List<Object> list = new ArrayList<Object>(); + StringTokenizer tokenizer = new StringTokenizer(mechanisms, " "); + while(tokenizer.hasMoreTokens()) + { + list.add(tokenizer.nextToken()); + } + return list; + } + + @Override public ServerSession getSession(Connection conn, SessionAttach atc) + { + + SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry); + + ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0); + //ssn.setSessionListener(new Echo()); + return ssn; + } + + + + + @Override + protected SaslServer createSaslServer(String mechanism) throws SaslException + { + return _appRegistry.getAuthenticationManager().createSaslServer(mechanism, _localFQDN); + + } + + + @Override public void connectionOpen(Connection conn, ConnectionOpen open) + { + ServerConnection sconn = (ServerConnection) conn; + + VirtualHost vhost; + String vhostName; + if(open.hasVirtualHost()) + { + vhostName = open.getVirtualHost(); + } + else + { + vhostName = ""; + } + vhost = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhostName); + + if(vhost != null) + { + sconn.setVirtualHost(vhost); + + sconn.invoke(new ConnectionOpenOk(Collections.EMPTY_LIST)); + + sconn.setState(Connection.State.OPEN); + } + else + { + sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown vistrulhost '"+vhostName+"'")); + sconn.setState(Connection.State.CLOSING); + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java new file mode 100644 index 0000000000..77dfbc0376 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -0,0 +1,398 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.*; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.security.PrincipalHolder; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.AMQException; + +import java.util.*; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.security.Principal; +import java.lang.ref.WeakReference; + +import static org.apache.qpid.util.Serial.*; +import com.sun.security.auth.UserPrincipal; + +public class ServerSession extends Session implements PrincipalHolder +{ + private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); + + public static interface MessageDispositionChangeListener + { + public void onAccept(); + + public void onRelease(); + + public void onReject(); + + public boolean acquire(); + + + } + + public static interface Task + { + public void doTask(ServerSession session); + } + + + private final SortedMap<Integer, MessageDispositionChangeListener> _messageDispositionListenerMap = + new ConcurrentSkipListMap<Integer, MessageDispositionChangeListener>(); + + private ServerTransaction _transaction; + + private Principal _principal; + + private Map<String, Subscription_0_10> _subscriptions = new ConcurrentHashMap<String, Subscription_0_10>(); + + private final List<Task> _taskList = new CopyOnWriteArrayList<Task>(); + + private final WeakReference<Session> _reference; + + + ServerSession(Connection connection, Binary name, long expiry) + { + super(connection, name, expiry); + + _transaction = new AutoCommitTransaction(this.getMessageStore()); + _principal = new UserPrincipal(connection.getAuthorizationID()); + _reference = new WeakReference(this); + } + + ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) + { + super(connection, delegate, name, expiry); + _transaction = new AutoCommitTransaction(this.getMessageStore()); + _principal = new UserPrincipal(connection.getAuthorizationID()); + _reference = new WeakReference(this); + } + + @Override + protected boolean isFull(int id) + { + return isCommandsFull(id); + } + + public void enqueue(final ServerMessage message, final ArrayList<AMQQueue> queues) + { + + _transaction.enqueue(queues,message, new ServerTransaction.Action() + { + + AMQQueue[] _queues = queues.toArray(new AMQQueue[queues.size()]); + + public void postCommit() + { + for(int i = 0; i < _queues.length; i++) + { + try + { + _queues[i].enqueue(message); + } + catch (AMQException e) + { + // TODO + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + throw new RuntimeException(e); + } + } + } + + public void onRollback() + { + // NO-OP + } + }); + + + } + + + public void sendMessage(MessageTransfer xfr, + Runnable postIdSettingAction) + { + invoke(xfr, postIdSettingAction); + } + + public void onMessageDispositionChange(MessageTransfer xfr, MessageDispositionChangeListener acceptListener) + { + _messageDispositionListenerMap.put(xfr.getId(), acceptListener); + } + + + private static interface MessageDispositionAction + { + void performAction(MessageDispositionChangeListener listener); + } + + public void accept(RangeSet ranges) + { + dispositionChange(ranges, new MessageDispositionAction() + { + public void performAction(MessageDispositionChangeListener listener) + { + listener.onAccept(); + } + }); + } + + + public void release(RangeSet ranges) + { + dispositionChange(ranges, new MessageDispositionAction() + { + public void performAction(MessageDispositionChangeListener listener) + { + listener.onRelease(); + } + }); + } + + public void reject(RangeSet ranges) + { + dispositionChange(ranges, new MessageDispositionAction() + { + public void performAction(MessageDispositionChangeListener listener) + { + listener.onReject(); + } + }); + } + + public RangeSet acquire(RangeSet transfers) + { + RangeSet acquired = new RangeSet(); + + if(!_messageDispositionListenerMap.isEmpty()) + { + Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); + Iterator<Range> rangeIter = transfers.iterator(); + + if(rangeIter.hasNext()) + { + Range range = rangeIter.next(); + + while(range != null && unacceptedMessages.hasNext()) + { + int next = unacceptedMessages.next(); + while(gt(next, range.getUpper())) + { + if(rangeIter.hasNext()) + { + range = rangeIter.next(); + } + else + { + range = null; + break; + } + } + if(range != null && range.includes(next)) + { + MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.get(next); + if(changeListener.acquire()) + { + acquired.add(next); + } + } + + + } + + } + + + } + + return acquired; + } + + public void dispositionChange(RangeSet ranges, MessageDispositionAction action) + { + if(ranges != null && !_messageDispositionListenerMap.isEmpty()) + { + Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); + Iterator<Range> rangeIter = ranges.iterator(); + + if(rangeIter.hasNext()) + { + Range range = rangeIter.next(); + + while(range != null && unacceptedMessages.hasNext()) + { + int next = unacceptedMessages.next(); + while(gt(next, range.getUpper())) + { + if(rangeIter.hasNext()) + { + range = rangeIter.next(); + } + else + { + range = null; + break; + } + } + if(range != null && range.includes(next)) + { + MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next); + action.performAction(changeListener); + } + + + } + + } + + } + } + + public void removeDispositionListener(Method method) + { + _messageDispositionListenerMap.remove(method.getId()); + } + + public void onClose() + { + _transaction.rollback(); + for(MessageDispositionChangeListener listener : _messageDispositionListenerMap.values()) + { + listener.onRelease(); + } + _messageDispositionListenerMap.clear(); + + for (Task task : _taskList) + { + task.doTask(this); + } + + } + + public void acknowledge(final Subscription_0_10 sub, final QueueEntry entry) + { + _transaction.dequeue(entry.getQueue(), entry.getMessage(), + new ServerTransaction.Action() + { + + public void postCommit() + { + sub.acknowledge(entry); + } + + public void onRollback() + { + entry.release(); + } + }); + } + + public Collection<Subscription_0_10> getSubscriptions() + { + return _subscriptions.values(); + } + + public void register(String destination, Subscription_0_10 sub) + { + _subscriptions.put(destination == null ? NULL_DESTINTATION : destination, sub); + } + + public Subscription_0_10 getSubscription(String destination) + { + return _subscriptions.get(destination == null ? NULL_DESTINTATION : destination); + } + + public void unregister(Subscription_0_10 sub) + { + _subscriptions.remove(sub.getConsumerTag().toString()); + try + { + sub.getSendLock(); + AMQQueue queue = sub.getQueue(); + if(queue != null) + { + queue.unregisterSubscription(sub); + } + + } + catch (AMQException e) + { + // TODO + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + finally + { + sub.releaseSendLock(); + } + } + + public void selectTx() + { + _transaction = new LocalTransaction(this.getMessageStore()); + } + + public void commit() + { + _transaction.commit(); + } + + public void rollback() + { + _transaction.rollback(); + } + + public Principal getPrincipal() + { + return _principal; + } + + public void addSessionCloseTask(Task task) + { + _taskList.add(task); + } + + public void removeSessionCloseTask(Task task) + { + _taskList.remove(task); + } + + public WeakReference<Session> getReference() + { + return _reference; + } + + public MessageStore getMessageStore() + { + return ((ServerConnection)getConnection()).getVirtualHost().getMessageStore(); + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java new file mode 100644 index 0000000000..df2754c16b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -0,0 +1,1193 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.transport; + +import org.apache.qpid.transport.*; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.exchange.*; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.flow.*; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +public class ServerSessionDelegate extends SessionDelegate +{ + private final IApplicationRegistry _appRegistry; + + public ServerSessionDelegate(IApplicationRegistry appRegistry) + { + _appRegistry = appRegistry; + } + + @Override + public void command(Session session, Method method) + { + super.command(session, method); + if (method.isSync()) + { + session.flushProcessed(); + } + } + + @Override + public void messageAccept(Session session, MessageAccept method) + { + ((ServerSession)session).accept(method.getTransfers()); + } + + + + @Override + public void messageReject(Session session, MessageReject method) + { + ((ServerSession)session).reject(method.getTransfers()); + } + + @Override + public void messageRelease(Session session, MessageRelease method) + { + ((ServerSession)session).release(method.getTransfers()); + } + + @Override + public void messageAcquire(Session session, MessageAcquire method) + { + RangeSet acquiredRanges = ((ServerSession)session).acquire(method.getTransfers()); + + Acquired result = new Acquired(acquiredRanges); + + + session.executionResult((int) method.getId(), result); + + + } + + @Override + public void messageResume(Session session, MessageResume method) + { + super.messageResume(session, method); + } + + @Override + public void messageSubscribe(Session session, MessageSubscribe method) + { + + //TODO - work around broken Python tests + if(!method.hasAcceptMode()) + { + method.setAcceptMode(MessageAcceptMode.EXPLICIT); + } + if(!method.hasAcquireMode()) + { + method.setAcquireMode(MessageAcquireMode.PRE_ACQUIRED); + + } + + /* if(!method.hasAcceptMode()) + { + exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "Accept-mode not supplied"); + } + else if(!method.hasAcquireMode()) + { + exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "Acquire-mode not supplied"); + } + else */if(!method.hasQueue()) + { + exception(session,method,ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not supplied"); + } + else + { + String destination = method.getDestination(); + + if(((ServerSession)session).getSubscription(destination)!=null) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Subscription already exists with destaination: '"+destination+"'"); + } + else + { + String queueName = method.getQueue(); + QueueRegistry queueRegistry = getQueueRegistry(session); + + + AMQQueue queue = queueRegistry.getQueue(queueName); + + if(queue == null) + { + exception(session,method,ExecutionErrorCode.NOT_FOUND, "Queue: " + queueName + " not found"); + } + else if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) + { + exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session"); + } + else + { + + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0L,0L); + + // TODO filters + + Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, + destination, + method.getAcceptMode(), + method.getAcquireMode(), + MessageFlowMode.WINDOW, + creditManager, null); + + ((ServerSession)session).register(destination, sub); + try + { + queue.registerSubscription(sub, method.getExclusive()); + } + catch (AMQQueue.ExistingExclusiveSubscription existing) + { + exception(session, method, ExecutionErrorCode.RESOURCE_LOCKED, "Queue has an exclusive consumer"); + } + catch (AMQQueue.ExistingSubscriptionPreventsExclusive exclusive) + { + exception(session, method, ExecutionErrorCode.RESOURCE_LOCKED, "Queue has an existing consumer - can't subscribe exclusively"); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + } + } + } + } + + + @Override + public void messageTransfer(Session ssn, MessageTransfer xfr) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(ssn); + Exchange exchange; + if(xfr.hasDestination()) + { + exchange = exchangeRegistry.getExchange(xfr.getDestination()); + if(exchange == null) + { + exchange = exchangeRegistry.getDefaultExchange(); + } + } + else + { + exchange = exchangeRegistry.getDefaultExchange(); + } + + + DeliveryProperties delvProps = null; + if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) + { + delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl()); + } + + MessageMetaData_0_10 messageMetaData = new MessageMetaData_0_10(xfr); + final MessageStore store = getVirtualHost(ssn).getMessageStore(); + StoredMessage<MessageMetaData_0_10> storeMessage = store.addMessage(messageMetaData); + storeMessage.addContent(0,xfr.getBody()); + storeMessage.flushToStore(); + MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference()); + + ArrayList<AMQQueue> queues = exchange.route(message); + + + + if(queues != null && queues.size() != 0) + { + ((ServerSession) ssn).enqueue(message, queues); + } + else + { + if(delvProps == null || !delvProps.hasDiscardUnroutable() || !delvProps.getDiscardUnroutable()) + { + if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT) + { + RangeSet rejects = new RangeSet(); + rejects.add(xfr.getId()); + MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable"); + ssn.invoke(reject); + } + else + { + Exchange alternate = exchange.getAlternateExchange(); + if(alternate != null) + { + queues = alternate.route(message); + if(queues != null && queues.size() != 0) + { + ((ServerSession) ssn).enqueue(message, queues); + } + else + { + //TODO - log the message discard + } + } + else + { + //TODO - log the message discard + } + + + } + } + + + } + + ssn.processed(xfr); + + } + + @Override + public void messageCancel(Session session, MessageCancel method) + { + String destination = method.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + else + { + ((ServerSession)session).unregister(sub); + } + } + + @Override + public void messageFlush(Session session, MessageFlush method) + { + String destination = method.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + else + { + + try + { + sub.flush(); + } + catch (AMQException e) + { + //TODO + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + throw new RuntimeException(e); + } + } + } + + @Override + public void txSelect(Session session, TxSelect method) + { + // TODO - check current tx mode + ((ServerSession)session).selectTx(); + } + + @Override + public void txCommit(Session session, TxCommit method) + { + // TODO - check current tx mode + ((ServerSession)session).commit(); + } + + @Override + public void txRollback(Session session, TxRollback method) + { + // TODO - check current tx mode + ((ServerSession)session).rollback(); + } + + + @Override + public void exchangeDeclare(Session session, ExchangeDeclare method) + { + String exchangeName = method.getExchange(); + VirtualHost virtualHost = getVirtualHost(session); + Exchange exchange = getExchange(session, exchangeName); + + if(method.getPassive()) + { + if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "not-found: exchange-name '"+exchangeName+"'"); + + } + else + { + // TODO - check exchange has same properties + if(!exchange.getType().toString().equals(method.getType())) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); + } + } + + } + else + { + if (!virtualHost.getAccessManager().authoriseCreateExchange((ServerSession)session, method.getAutoDelete(), + method.getDurable(), new AMQShortString(method.getExchange()), false, false, method.getPassive(), + new AMQShortString(method.getType()))) + { + + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + String description = "permission denied: exchange-name '" + exchangeName + "'"; + + exception(session, method, errorCode, description); + + + } + else if(exchange == null) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); + ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); + + + + try + { + + exchange = exchangeFactory.createExchange(method.getExchange(), + method.getType(), + method.getDurable(), + method.getAutoDelete()); + + String alternateExchangeName = method.getAlternateExchange(); + if(alternateExchangeName != null && alternateExchangeName.length() != 0) + { + Exchange alternate = getExchange(session, alternateExchangeName); + exchange.setAlternateExchange(alternate); + } + + if (exchange.isDurable() && !exchange.isAutoDelete()) + { + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.createExchange(exchange); + } + + exchangeRegistry.registerExchange(exchange); + } + catch(AMQUnknownExchangeType e) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType()); + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + + } + else + { + if(!exchange.getType().toString().equals(method.getType())) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot redeclare with a different exchange type"); + } + } + + } + } + + private void exception(Session session, Method method, ExecutionErrorCode errorCode, String description) + { + ExecutionException ex = new ExecutionException(); + ex.setErrorCode(errorCode); + ex.setCommandId(method.getId()); + ex.setDescription(description); + + session.invoke(ex); + + } + + private Exchange getExchange(Session session, String exchangeName) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); + return exchangeRegistry.getExchange(exchangeName); + } + + private ExchangeRegistry getExchangeRegistry(Session session) + { + VirtualHost virtualHost = getVirtualHost(session); + return virtualHost.getExchangeRegistry(); + + } + + private VirtualHost getVirtualHost(Session session) + { + ServerConnection conn = getServerConnection(session); + VirtualHost vhost = conn.getVirtualHost(); + return vhost; + } + + private ServerConnection getServerConnection(Session session) + { + ServerConnection conn = (ServerConnection) session.getConnection(); + return conn; + } + + @Override + public void exchangeDelete(Session session, ExchangeDelete method) + { + VirtualHost virtualHost = getVirtualHost(session); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseDelete((ServerSession)session, + exchangeRegistry.getExchange(method.getExchange()))) + { + exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); + + } + else + { + + try + { + Exchange exchange = getExchange(session, method.getExchange()); + + if(exchange != null && exchange.hasReferrers()) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); + } + else + { + exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); + + if (exchange.isDurable() && !exchange.isAutoDelete()) + { + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeExchange(exchange); + } + + } + } + catch (ExchangeInUseException e) + { + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + } + + } + + @Override + public void exchangeQuery(Session session, ExchangeQuery method) + { + + ExchangeQueryResult result = new ExchangeQueryResult(); + + Exchange exchange = getExchange(session, method.getName()); + + if(exchange != null) + { + result.setDurable(exchange.isDurable()); + result.setType(exchange.getType().toString()); + result.setNotFound(false); + } + else + { + result.setNotFound(true); + } + + session.executionResult((int) method.getId(), result); + } + + @Override + public void exchangeBind(Session session, ExchangeBind method) + { + + VirtualHost virtualHost = getVirtualHost(session); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + if (!method.hasQueue()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not set"); + } + else if (!method.hasExchange()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "exchange not set"); + } +/* + else if (!method.hasBindingKey()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "binding-key not set"); + } +*/ + else + { + //TODO - here because of non-compiant python tests + if (!method.hasBindingKey()) + { + method.setBindingKey(method.getQueue()); + } + AMQQueue queue = queueRegistry.getQueue(method.getQueue()); + Exchange exchange = exchangeRegistry.getExchange(method.getExchange()); + if(queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Queue: '" + method.getQueue() + "' not found"); + } + else if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found"); + } + else if (!virtualHost.getAccessManager().authoriseBind((ServerSession)session, exchange, + queue, new AMQShortString(method.getBindingKey()))) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() + + "' to Queue: '" + method.getQueue() + + "' not allowed"); + } + else if(exchange.getType().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) + { + exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header"); + } + else + { + try + { + AMQShortString routingKey = new AMQShortString(method.getBindingKey()); + FieldTable fieldTable = FieldTable.convertToFieldTable(method.getArguments()); + + if (!exchange.isBound(routingKey, fieldTable, queue)) + { + queue.bind(exchange, routingKey, fieldTable); + + } + else + { + // todo + } + } + catch (AMQException e) + { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + } + + + } + + + + } + + @Override + public void exchangeUnbind(Session session, ExchangeUnbind method) + { + VirtualHost virtualHost = getVirtualHost(session); + ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); + QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); + + if (!method.hasQueue()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "queue not set"); + } + else if (!method.hasExchange()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "exchange not set"); + } + else if (!method.hasBindingKey()) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "binding-key not set"); + } + else + { + AMQQueue queue = queueRegistry.getQueue(method.getQueue()); + Exchange exchange = exchangeRegistry.getExchange(method.getExchange()); + if(queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Queue: '" + method.getQueue() + "' not found"); + } + else if(exchange == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found"); + } + else + { + try + { + queue.unBind(exchange, new AMQShortString(method.getBindingKey()), null); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + } + + + super.exchangeUnbind(session, method); + } + + @Override + public void exchangeBound(Session session, ExchangeBound method) + { + + ExchangeBoundResult result = new ExchangeBoundResult(); + Exchange exchange; + AMQQueue queue; + if(method.hasExchange()) + { + exchange = getExchange(session, method.getExchange()); + + if(exchange == null) + { + result.setExchangeNotFound(true); + } + } + else + { + exchange = getExchangeRegistry(session).getDefaultExchange(); + } + + + if(method.hasQueue()) + { + + queue = getQueue(session, method.getQueue()); + if(queue == null) + { + result.setQueueNotFound(true); + } + + + if(exchange != null && queue != null) + { + + boolean queueMatched = exchange.isBound(queue); + + result.setQueueNotMatched(!queueMatched); + + + if(method.hasBindingKey()) + { + + if(method.hasArguments()) + { + // TODO + } + if(queueMatched) + { + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey(), queue)); + } + else + { + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey())); + } + } + else if (method.hasArguments()) + { + // TODO + + } + + result.setQueueNotMatched(!exchange.isBound(queue)); + + } + else if(exchange != null && method.hasBindingKey()) + { + if(method.hasArguments()) + { + // TODO + } + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey())); + + } + + } + else if(exchange != null && method.hasBindingKey()) + { + if(method.hasArguments()) + { + // TODO + } + result.setKeyNotMatched(!exchange.isBound(method.getBindingKey())); + + } + + + session.executionResult((int) method.getId(), result); + + + } + + private AMQQueue getQueue(Session session, String queue) + { + QueueRegistry queueRegistry = getQueueRegistry(session); + return queueRegistry.getQueue(queue); + } + + private QueueRegistry getQueueRegistry(Session session) + { + return getVirtualHost(session).getQueueRegistry(); + } + + @Override + public void queueDeclare(Session session, QueueDeclare method) + { + + VirtualHost virtualHost = getVirtualHost(session); + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + + String queueName = method.getQueue(); + + if (!method.getPassive()) + { + // Perform ACL if request is not passive + + if (!virtualHost.getAccessManager().authoriseCreateQueue(((ServerSession)session), method.getAutoDelete(), method.getDurable(), + method.getExclusive(), false, method.getPassive(), new AMQShortString(queueName))) + { + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + String description = "permission denied: queue-name '" + queueName + "'"; + + exception(session, method, errorCode, description); + + // TODO control flow + return; + } + } + + + AMQQueue queue; + QueueRegistry queueRegistry = getQueueRegistry(session); + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + + synchronized (queueRegistry) + { + + if (((queue = queueRegistry.getQueue(queueName)) == null)) + { + + if (method.getPassive()) + { + String description = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_FOUND; + + exception(session, method, errorCode, description); + + return; + } + else + { + try + { + queue = createQueue(queueName, method, virtualHost, (ServerSession)session); + if(method.getExclusive()) + { + queue.setPrincipalHolder((ServerSession)session); + queue.setExclusiveOwner(session); + } + final String alternateExchangeName = method.getAlternateExchange(); + if(alternateExchangeName != null && alternateExchangeName.length() != 0) + { + Exchange alternate = getExchange(session, alternateExchangeName); + queue.setAlternateExchange(alternate); + } + + if(method.hasArguments() && method.getArguments() != null) + { + if(method.getArguments().containsKey("no-local")) + { + Object no_local = method.getArguments().get("no-local"); + if(no_local instanceof Boolean && ((Boolean)no_local)) + { + queue.setNoLocal(true); + } + } + } + + + if (queue.isDurable() && !queue.isAutoDelete()) + { + if(method.hasArguments() && method.getArguments() != null) + { + Map<String,Object> args = method.getArguments(); + FieldTable ftArgs = new FieldTable(); + for(Map.Entry<String, Object> entry : args.entrySet()) + { + ftArgs.put(new AMQShortString(entry.getKey()), entry.getValue()); + } + store.createQueue(queue, ftArgs); + } + else + { + store.createQueue(queue); + } + } + queueRegistry.registerQueue(queue); + boolean autoRegister = ApplicationRegistry.getInstance().getConfiguration().getQueueAutoRegister(); + + if (autoRegister) + { + ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); + + Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); + + queue.bind(defaultExchange, new AMQShortString(queueName), null); + + } + + if(method.hasAutoDelete() + && method.getAutoDelete() + && method.hasExclusive() + && method.getExclusive()) + { + final AMQQueue q = queue; + final ServerSession.Task deleteQueueTask = new ServerSession.Task() + { + + public void doTask(ServerSession session) + { + try + { + q.delete(); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + }; + final ServerSession s = (ServerSession) session; + s.addSessionCloseTask(deleteQueueTask); + queue.addQueueDeleteTask(new AMQQueue.Task() + { + + public void doTask(AMQQueue queue) throws AMQException + { + s.removeSessionCloseTask(deleteQueueTask); + } + }); + } + else if(method.getExclusive()) + { + { + final AMQQueue q = queue; + final ServerSession.Task removeExclusive = new ServerSession.Task() + { + + public void doTask(ServerSession session) + { + q.setPrincipalHolder(null); + } + }; + final ServerSession s = (ServerSession) session; + s.addSessionCloseTask(removeExclusive); + queue.addQueueDeleteTask(new AMQQueue.Task() + { + + public void doTask(AMQQueue queue) throws AMQException + { + s.removeSessionCloseTask(removeExclusive); + } + }); + } + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + } + else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session))) + { + + String description = "Cannot declare queue('" + queueName + "')," + + " as exclusive queue with same name " + + "declared on another session"; + ExecutionErrorCode errorCode = ExecutionErrorCode.RESOURCE_LOCKED; + + exception(session, method, errorCode, description); + + return; + } + + } + } + + + protected AMQQueue createQueue(final String queueName, + QueueDeclare body, + VirtualHost virtualHost, + final ServerSession session) + throws AMQException + { + final QueueRegistry registry = virtualHost.getQueueRegistry(); + + String owner = body.getExclusive() ? session.getPrincipal().getName() : null; + + final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), virtualHost, + body.getArguments()); + + + if (body.getExclusive() && !body.getDurable()) + { + final ServerSession.Task deleteQueueTask = + new ServerSession.Task() + { + public void doTask(ServerSession session) + { + if (registry.getQueue(queueName) == queue) + { + try + { + queue.delete(); + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + } + } + }; + + session.addSessionCloseTask(deleteQueueTask); + + queue.addQueueDeleteTask(new AMQQueue.Task() + { + public void doTask(AMQQueue queue) + { + session.removeSessionCloseTask(deleteQueueTask); + } + }); + }// if exclusive and not durable + + return queue; + } + + @Override + public void queueDelete(Session session, QueueDelete method) + { + + String queueName = method.getQueue(); + if(queueName == null || queueName.length()==0) + { + exception(session, method, ExecutionErrorCode.INVALID_ARGUMENT, "No queue name supplied"); + + } + else + { + AMQQueue queue = getQueue(session, queueName); + + + if (queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found"); + } + else + { + if(queue.getPrincipalHolder() != null && queue.getPrincipalHolder() != session) + { + exception(session,method,ExecutionErrorCode.RESOURCE_LOCKED, "Exclusive Queue: " + queueName + " owned exclusively by another session"); + } + else if (method.getIfEmpty() && !queue.isEmpty()) + { + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Queue " + queueName + " not empty"); + } + else if (method.getIfUnused() && !queue.isUnused()) + { + // TODO - Error code + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Queue " + queueName + " in use"); + + } + else + { + VirtualHost virtualHost = getVirtualHost(session); + + //Perform ACLs + if (!virtualHost.getAccessManager().authoriseDelete(((ServerSession)session), queue)) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot delete queue " + queueName); + } + else + { + try + { + int purged = queue.delete(); + if (queue.isDurable() && !queue.isAutoDelete()) + { + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeQueue(queue); + } + + } + catch (AMQException e) + { + //TODO + throw new RuntimeException(e); + } + + } + + } + } + } + + } + + @Override + public void queuePurge(Session session, QueuePurge method) + { + String queueName = method.getQueue(); + if(queueName == null || queueName.length()==0) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "No queue name supplied"); + + } + else + { + AMQQueue queue = getQueue(session, queueName); + + + if (queue == null) + { + exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found"); + } + else + { + //TODO + queue.clearQueue(); + } + } + + } + + @Override + public void queueQuery(Session session, QueueQuery method) + { + QueueQueryResult result = new QueueQueryResult(); + + AMQQueue queue = getQueue(session, method.getQueue()); + + if(queue != null) + { + result.setQueue(queue.getName().toString()); + result.setDurable(queue.isDurable()); + result.setExclusive(queue.isExclusive()); + result.setAutoDelete(queue.isAutoDelete()); + result.setArguments(queue.getArguments()); + result.setMessageCount(queue.getMessageCount()); + result.setSubscriberCount(queue.getConsumerCount()); + + } + + + session.executionResult((int) method.getId(), result); + + } + + @Override + public void messageSetFlowMode(Session session, MessageSetFlowMode sfm) + { + String destination = sfm.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, sfm, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + + if(sub.isStopped()) + { + sub.setFlowMode(sfm.getFlowMode()); + } + } + + @Override + public void messageStop(Session session, MessageStop stop) + { + String destination = stop.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, stop, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + + sub.stop(); + + } + + @Override + public void messageFlow(Session session, MessageFlow flow) + { + String destination = flow.getDestination(); + + Subscription_0_10 sub = ((ServerSession)session).getSubscription(destination); + + if(sub == null) + { + exception(session, flow, ExecutionErrorCode.NOT_FOUND, "not-found: destination '"+destination+"'"); + } + + sub.addCredit(flow.getUnit(), flow.getValue()); + + } + + @Override + public void closed(Session session) + { + super.closed(session); + for(Subscription_0_10 sub : getSubscriptions(session)) + { + ((ServerSession)session).unregister(sub); + } + ((ServerSession)session).onClose(); + } + + public Collection<Subscription_0_10> getSubscriptions(Session session) + { + return ((ServerSession)session).getSubscriptions(); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java new file mode 100755 index 0000000000..7b29106ba6 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -0,0 +1,170 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.Collection; + +public class AutoCommitTransaction implements ServerTransaction +{ + + private final TransactionLog _transactionLog; + + public AutoCommitTransaction(TransactionLog transactionLog) + { + _transactionLog = transactionLog; + } + + + public void addPostCommitAction(Action postCommitAction) + { + postCommitAction.postCommit(); + } + + public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + + try + { + if(message.isPersistent() && queue.isDurable()) + { + + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn.dequeueMessage(queue, message.getMessageNumber()); + // store.remove enqueue + // store.commit + txn.commitTran(); + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + } + + public void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction) + { + try + { + TransactionLog.Transaction txn = null; + for(QueueEntry entry : ackedMessages) + { + ServerMessage message = entry.getMessage(); + AMQQueue queue = entry.getQueue(); + + if(message.isPersistent() && queue.isDurable()) + { + if(txn == null) + { + txn = _transactionLog.newTransaction(); + } + txn.dequeueMessage(queue, message.getMessageNumber()); + } + + } + if(txn != null) + { + txn.commitTran(); + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + } + + + public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + try + { + if(message.isPersistent() && queue.isDurable()) + { + + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn.enqueueMessage(queue, message.getMessageNumber()); + txn.commitTran(); + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + e.printStackTrace(); + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + + } + + public void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction) + { + try + { + + if(message.isPersistent()) + { + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + Long id = message.getMessageNumber(); + for(AMQQueue q : queues) + { + if(q.isDurable()) + { + txn.enqueueMessage(q, id); + } + } + txn.commitTran(); + + } + postCommitAction.postCommit(); + } + catch (AMQException e) + { + //TODO + postCommitAction.onRollback(); + throw new RuntimeException(e); + } + + } + + public void commit() + { + + } + + public void rollback() + { + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java new file mode 100755 index 0000000000..9997fbe767 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -0,0 +1,243 @@ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.AMQException; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; + +public class LocalTransaction implements ServerTransaction +{ + private final List<Action> _postCommitActions = new ArrayList<Action>(); + + private volatile TransactionLog.Transaction _transaction; + private TransactionLog _transactionLog; + + public LocalTransaction(TransactionLog transactionLog) + { + _transactionLog = transactionLog; + } + + public void addPostCommitAction(Action postCommitAction) + { + _postCommitActions.add(postCommitAction); + } + + public void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + if(message.isPersistent() && queue.isDurable()) + { + try + { + + beginTranIfNecessary(); + _transaction.dequeueMessage(queue, message.getMessageNumber()); + + } + catch(AMQException e) + { + tidyUpOnError(e); + } + } + _postCommitActions.add(postCommitAction); + } + + public void dequeue(Collection<QueueEntry> queueEntries, Action postCommitAction) + { + try + { + + for(QueueEntry entry : queueEntries) + { + ServerMessage message = entry.getMessage(); + AMQQueue queue = entry.getQueue(); + if(message.isPersistent() && queue.isDurable()) + { + beginTranIfNecessary(); + _transaction.dequeueMessage(queue, message.getMessageNumber()); + } + + } + } + catch(AMQException e) + { + tidyUpOnError(e); + } + _postCommitActions.add(postCommitAction); + + } + + private void tidyUpOnError(Exception e) + { + try + { + for(Action action : _postCommitActions) + { + action.onRollback(); + } + } + finally + { + try + { + _transaction.abortTran(); + } + catch (Exception e1) + { + // TODO could try to chain the information to the original error + } + _transaction = null; + _postCommitActions.clear(); + } + + throw new RuntimeException(e); + } + + private void beginTranIfNecessary() + { + if(_transaction == null) + { + try + { + _transaction = _transactionLog.newTransaction(); + } + catch (Exception e) + { + tidyUpOnError(e); + } + } + } + + public void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction) + { + if(message.isPersistent() && queue.isDurable()) + { + beginTranIfNecessary(); + try + { + _transaction.enqueueMessage(queue, message.getMessageNumber()); + } + catch (Exception e) + { + tidyUpOnError(e); + } + } + _postCommitActions.add(postCommitAction); + + + } + + public void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction) + { + + + if(message.isPersistent()) + { + if(_transaction == null) + { + for(AMQQueue queue : queues) + { + if(queue.isDurable()) + { + beginTranIfNecessary(); + break; + } + } + + + } + + + try + { + for(AMQQueue queue : queues) + { + if(queue.isDurable()) + { + _transaction.enqueueMessage(queue, message.getMessageNumber()); + } + } + + } + catch (Exception e) + { + tidyUpOnError(e); + } + } + _postCommitActions.add(postCommitAction); + + + } + + public void commit() + { + try + { + if(_transaction != null) + { + + _transaction.commitTran(); + } + + for(Action action : _postCommitActions) + { + action.postCommit(); + } + } + catch (Exception e) + { + for(Action action : _postCommitActions) + { + action.onRollback(); + } + //TODO + throw new RuntimeException(e); + } + finally + { + _transaction = null; + _postCommitActions.clear(); + } + + } + + public void rollback() + { + + try + { + + if(_transaction != null) + { + + _transaction.abortTran(); + } + } + catch (AMQException e) + { + //TODO + e.printStackTrace(); + throw new RuntimeException(e); + } + finally + { + try + { + for(Action action : _postCommitActions) + { + action.onRollback(); + } + } + finally + { + _transaction = null; + _postCommitActions.clear(); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java deleted file mode 100644 index 450852cef7..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ack.TxAck; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -import java.util.List; -import java.util.ArrayList; - -/** A transactional context that only supports local transactions. */ -public class LocalTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(LocalTransactionalContext.class); - - private final TxnBuffer _txnBuffer = new TxnBuffer(); - - private final List<DeliveryAction> _postCommitDeliveryList = new ArrayList<DeliveryAction>(); - - /** - * We keep hold of the ack operation so that we can consolidate acks, i.e. multiple acks within a txn are - * consolidated into a single operation - */ - private TxAck _ackOp; - - private boolean _inTran = false; - - /** Are there messages to deliver. NOT Has the message been delivered */ - private boolean _messageDelivered = false; - private final AMQChannel _channel; - - - private abstract class DeliveryAction - { - - abstract public void process() throws AMQException; - - } - - private class RequeueAction extends DeliveryAction - { - public QueueEntry entry; - - public RequeueAction(QueueEntry entry) - { - this.entry = entry; - } - - public void process() throws AMQException - { - entry.requeue(getStoreContext()); - } - } - - private class PublishAction extends DeliveryAction - { - private final AMQQueue _queue; - private final AMQMessage _message; - - public PublishAction(final AMQQueue queue, final AMQMessage message) - { - _queue = queue; - _message = message; - } - - public void process() throws AMQException - { - - _message.incrementReference(); - try - { - QueueEntry entry = _queue.enqueue(getStoreContext(),_message); - _queue.checkCapacity(_channel); - - if(entry.immediateAndNotDelivered()) - { - getReturnMessages().add(new NoConsumersException(_message)); - } - } - finally - { - _message.decrementReference(getStoreContext()); - } - } - } - - public LocalTransactionalContext(final AMQChannel channel) - { - _channel = channel; - } - - public StoreContext getStoreContext() - { - return _channel.getStoreContext(); - } - - public List<RequiredDeliveryException> getReturnMessages() - { - return _channel.getReturnMessages(); - } - - public MessageStore getMessageStore() - { - return _channel.getMessageStore(); - } - - - public void rollback() throws AMQException - { - _txnBuffer.rollback(getStoreContext()); - // Hack to deal with uncommitted non-transactional writes - if (getMessageStore().inTran(getStoreContext())) - { - getMessageStore().abortTran(getStoreContext()); - _inTran = false; - } - - _postCommitDeliveryList.clear(); - } - - public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException - { - // A publication will result in the enlisting of several - // TxnOps. The first is an op that will store the message. - // Following that (and ordering is important), an op will - // be added for every queue onto which the message is - // enqueued. - _postCommitDeliveryList.add(new PublishAction(queue, message)); - _messageDelivered = true; - - } - - public void requeue(QueueEntry entry) throws AMQException - { - _postCommitDeliveryList.add(new RequeueAction(entry)); - _messageDelivered = true; - - } - - - private void checkAck(long deliveryTag, UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Ack with delivery tag " + deliveryTag + " not known for channel"); - } - } - - public void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException - { - // check that the tag exists to give early failure - if (!multiple || (deliveryTag > 0)) - { - checkAck(deliveryTag, unacknowledgedMessageMap); - } - // we use a single txn op for all acks and update this op - // as new acks come in. If this is the first ack in the txn - // we will need to create and enlist the op. - if (_ackOp == null) - { - _ackOp = new TxAck(unacknowledgedMessageMap); - _txnBuffer.enlist(_ackOp); - } - // update the op to include this ack request - if (multiple && (deliveryTag == 0)) - { - // if have signalled to ack all, that refers only - // to all at this time - _ackOp.update(lastDeliveryTag, multiple); - } - else - { - _ackOp.update(deliveryTag, multiple); - } - if(!_inTran && _ackOp.checkPersistent()) - { - beginTranIfNecessary(); - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - // Not required in this transactional context - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - // Not required in this transactional context - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - if (_log.isDebugEnabled()) - { - _log.debug("Starting transaction on message store: " + this); - } - - getMessageStore().beginTran(getStoreContext()); - _inTran = true; - } - } - - public void commit() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing transactional context: " + this); - } - - if (_ackOp != null) - { - - _messageDelivered = true; - _ackOp.consolidate(); - // already enlisted, after commit will reset regardless of outcome - _ackOp = null; - } - - if (_messageDelivered && _inTran) - { - _txnBuffer.enlist(new StoreMessageOperation(getMessageStore())); - } - // fixme fail commit here ... QPID-440 - try - { - _txnBuffer.commit(getStoreContext()); - } - finally - { - _messageDelivered = false; - _inTran = getMessageStore().inTran(getStoreContext()); - } - - try - { - postCommitDelivery(); - } - catch (AMQException e) - { - // OK so what do we do now...? - _log.error("Failed to deliver messages following txn commit: " + e, e); - } - } - - private void postCommitDelivery() throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Performing post commit delivery"); - } - - try - { - for (DeliveryAction dd : _postCommitDeliveryList) - { - dd.process(); - } - } - finally - { - _postCommitDeliveryList.clear(); - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java deleted file mode 100644 index 10d6021d27..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/NonTransactionalContext.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.*; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** @author Apache Software Foundation */ -public class NonTransactionalContext implements TransactionalContext -{ - private static final Logger _log = Logger.getLogger(NonTransactionalContext.class); - - /** Channel is useful for logging */ - private final AMQChannel _channel; - - /** Where to put undeliverable messages */ - private final List<RequiredDeliveryException> _returnMessages; - - - - private final MessageStore _messageStore; - - private final StoreContext _storeContext; - - /** Whether we are in a transaction */ - private boolean _inTran; - - public NonTransactionalContext(MessageStore messageStore, StoreContext storeContext, AMQChannel channel, - List<RequiredDeliveryException> returnMessages) - { - _channel = channel; - _storeContext = storeContext; - _returnMessages = returnMessages; - _messageStore = messageStore; - - } - - - public StoreContext getStoreContext() - { - return _storeContext; - } - - public void beginTranIfNecessary() throws AMQException - { - if (!_inTran) - { - _messageStore.beginTran(_storeContext); - _inTran = true; - } - } - - public void commit() throws AMQException - { - // Does not apply to this context - } - - public void rollback() throws AMQException - { - // Does not apply to this context - } - - public void deliver(final AMQQueue queue, AMQMessage message) throws AMQException - { - QueueEntry entry = queue.enqueue(_storeContext, message); - queue.checkCapacity(_channel); - - - //following check implements the functionality - //required by the 'immediate' flag: - if(entry.immediateAndNotDelivered()) - { - _returnMessages.add(new NoConsumersException(entry.getMessage())); - } - - } - - public void requeue(QueueEntry entry) throws AMQException - { - entry.requeue(_storeContext); - } - - public void acknowledgeMessage(final long deliveryTag, long lastDeliveryTag, - boolean multiple, final UnacknowledgedMessageMap unacknowledgedMessageMap) - throws AMQException - { - - final boolean debug = _log.isDebugEnabled(); - ; - if (multiple) - { - if (deliveryTag == 0) - { - - //Spec 2.1.6.11 ... If the multiple field is 1, and the delivery tag is zero, - // tells the server to acknowledge all outstanding mesages. - _log.info("Multiple ack on delivery tag 0. ACKing all messages. Current count:" + - unacknowledgedMessageMap.size()); - unacknowledgedMessageMap.visit(new UnacknowledgedMessageMap.Visitor() - { - public boolean callback(final long deliveryTag, QueueEntry message) throws AMQException - { - if (debug) - { - _log.debug("Discarding message: " + message.getMessage().getMessageId()); - } - if(message.getMessage().isPersistent()) - { - beginTranIfNecessary(); - } - //Message has been ack so discard it. This will dequeue and decrement the reference. - message.discard(_storeContext); - - return false; - } - - public void visitComplete() - { - unacknowledgedMessageMap.clear(); - } - }); - } - else - { - if (!unacknowledgedMessageMap.contains(deliveryTag)) - { - throw new AMQException("Multiple ack on delivery tag " + deliveryTag + " not known for channel"); - } - - unacknowledgedMessageMap.drainTo(deliveryTag, _storeContext); - } - } - else - { - QueueEntry msg; - msg = unacknowledgedMessageMap.get(deliveryTag); - - if (msg == null) - { - _log.info("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - throw new AMQException("Single ack on delivery tag " + deliveryTag + " not known for channel:" + - _channel.getChannelId()); - } - - if (debug) - { - _log.debug("Discarding message: " + msg.getMessage().getMessageId()); - } - if(msg.getMessage().isPersistent()) - { - beginTranIfNecessary(); - } - - //Message has been ack so discard it. This will dequeue and decrement the reference. - msg.discard(_storeContext); - - unacknowledgedMessageMap.remove(deliveryTag); - - - if (debug) - { - _log.debug("Received non-multiple ack for messaging with delivery tag " + deliveryTag + " msg id " + - msg.getMessage().getMessageId()); - } - } - if(_inTran) - { - _messageStore.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageFullyReceived(boolean persistent) throws AMQException - { - if (persistent) - { - _messageStore.commitTran(_storeContext); - _inTran = false; - } - } - - public void messageProcessed(AMQProtocolSession protocolSession) throws AMQException - { - _channel.processReturns(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java new file mode 100755 index 0000000000..88bdc363c4 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.txn; + +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.AMQChannel; + +import java.util.List; +import java.util.SortedSet; +import java.util.Collection; + +public interface ServerTransaction +{ + + void addPostCommitAction(Action postCommitAction); + + + + + public static interface Action + { + public void postCommit(); + + public void onRollback(); + } + + void dequeue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + + void dequeue(Collection<QueueEntry> ackedMessages, Action postCommitAction); + + void enqueue(AMQQueue queue, EnqueableMessage message, Action postCommitAction); + + void enqueue(List<AMQQueue> queues, EnqueableMessage message, Action postCommitAction); + + + void commit(); + + void rollback(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java deleted file mode 100644 index 0e4d6c2030..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/StoreMessageOperation.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -/** - * A transactional operation to store messages in an underlying persistent store. When this operation - * commits it will do everything to ensure that all messages are safely committed to persistent - * storage. - */ -public class StoreMessageOperation implements TxnOp -{ - private final MessageStore _messsageStore; - - public StoreMessageOperation(MessageStore messageStore) - { - _messsageStore = messageStore; - } - - public void prepare(StoreContext context) throws AMQException - { - } - - public void undoPrepare() - { - } - - public void commit(StoreContext context) throws AMQException - { - _messsageStore.commitTran(context); - } - - public void rollback(StoreContext context) throws AMQException - { - _messsageStore.abortTran(context); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java deleted file mode 100644 index 647ba66fb4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TransactionalContext.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.ack.UnacknowledgedMessageMap; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.StoreContext; - -/** - * TransactionalContext provides a context in which transactional operations on {@link AMQMessage}s are performed. - * Different levels of transactional support for the delivery of messages may be provided by different implementations - * of this interface. - * - * <p/>The fundamental transactional operations that can be performed on a message queue are 'enqueue' and 'dequeue'. - * In this interface, these have been recast as the {@link #messageFullyReceived} and {@link #acknowledgeMessage} - * operations. This interface essentially provides a way to make enqueueing and dequeuing transactional. - * - * <p/><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities - * <tr><td> Explicitly accept a transaction start notification. - * <tr><td> Commit all pending operations in a transaction. - * <tr><td> Rollback all pending operations in a transaction. - * <tr><td> Deliver a message to a queue as part of a transaction. - * <tr><td> Redeliver a message to a queue as part of a transaction. - * <tr><td> Mark a message as acknowledged as part of a transaction. - * <tr><td> Accept notification that a message has been completely received as part of a transaction. - * <tr><td> Accept notification that a message has been fully processed as part of a transaction. - * <tr><td> Associate a message store context with this transaction context. - * </table> - * - * @todo The 'fullyReceived' and 'messageProcessed' events sit uncomfortably in the responsibilities of a transactional - * context. They are non-transactional operations, used to trigger other side-effects. Consider moving them - * somewhere else, a seperate interface for example. - * - * @todo This transactional context could be written as a wrapper extension to a Queue implementation, that provides - * transactional management of the enqueue and dequeue operations, with added commit/rollback methods. Any - * queue implementation could be made transactional by wrapping it as a transactional queue. This would mean - * that the enqueue/dequeue operations do not need to be recast as deliver/acknowledge operations, which may be - * conceptually neater. - * - * For example: - * <pre> - * public interface Transactional - * { - * public void commit(); - * public void rollback(); - * } - * - * public interface TransactionalQueue<E> extends Transactional, SizeableQueue<E> - * {} - * - * public class Queues - * { - * ... - * // For transactional messaging, take a transactional view onto the queue. - * public static <E> TransactionalQueue<E> getTransactionalQueue(SizeableQueue<E> queue) { ... } - * - * // For non-transactional messaging, take a non-transactional view onto the queue. - * public static <E> TransactionalQueue<E> getNonTransactionalQueue(SizeableQueue<E> queue) { ... } - * } - * </pre> - */ -public interface TransactionalContext -{ - /** - * Explicitly begins the transaction, if it has not already been started. {@link #commit} or {@link #rollback} - * should automatically begin the next transaction in the chain. - * - * @throws AMQException If the transaction cannot be started for any reason. - */ - void beginTranIfNecessary() throws AMQException; - - /** - * Makes all pending operations on the transaction permanent and visible. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void commit() throws AMQException; - - /** - * Erases all pending operations on the transaction. - * - * @throws AMQException If the transaction cannot be committed for any reason. - */ - void rollback() throws AMQException; - - /** - * Delivers the specified message to the specified queue. - * - * <p/>This is an 'enqueue' operation. - * - * @param queue - * @param message The message to deliver - * @throws AMQException If the message cannot be delivered for any reason. - */ - void deliver(final AMQQueue queue, AMQMessage message) throws AMQException; - - /** - * Requeues the specified message entry (message queue pair) - * - * - * @param queueEntry The message,queue pair - * - * @throws AMQException If the message cannot be delivered for any reason. - */ - void requeue(QueueEntry queueEntry) throws AMQException; - - - /** - * Acknowledges a message or many messages as delivered. All messages up to a specified one, may be acknowledged by - * setting the 'multiple' flag. It is also possible for the acknowledged message id to be zero, when the 'multiple' - * flag is set, in which case an acknowledgement up to the latest delivered message should be done. - * - * <p/>This is a 'dequeue' operation. - * - * @param deliveryTag The id of the message to acknowledge, or zero, if using multiple acknowledgement - * up to the latest message. - * @param lastDeliveryTag The latest message delivered. - * @param multiple <tt>true</tt> if all message ids up the acknowledged one or latest delivered, are - * to be acknowledged, <tt>false</tt> otherwise. - * @param unacknowledgedMessageMap The unacknowledged messages in the transaction, to remove the acknowledged message - * from. - * - * @throws AMQException If the message cannot be acknowledged for any reason. - */ - void acknowledgeMessage(long deliveryTag, long lastDeliveryTag, boolean multiple, - UnacknowledgedMessageMap unacknowledgedMessageMap) throws AMQException; - - /** - * Notifies the transactional context that a message has been fully received. The actual message that was received - * is not specified. This event may be used to trigger a process related to the receipt of the message, for example, - * flushing its data to disk. - * - * @param persistent <tt>true</tt> if the received message is persistent, <tt>false</tt> otherwise. - * - * @throws AMQException If the fully received event cannot be processed for any reason. - */ - void messageFullyReceived(boolean persistent) throws AMQException; - - /** - * Notifies the transactional context that a message has been delivered, succesfully or otherwise. The actual - * message that was delivered is not specified. This event may be used to trigger a process related to the - * outcome of the delivery of the message, for example, cleaning up failed deliveries. - * - * @param protocolSession The protocol session of the deliverable message. - * - * @throws AMQException If the message processed event cannot be handled for any reason. - */ - void messageProcessed(AMQProtocolSession protocolSession) throws AMQException; - - /** - * Gets the message store context associated with this transactional context. - * - * @return The message store context associated with this transactional context. - */ - StoreContext getStoreContext(); -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java deleted file mode 100644 index 46a68b6a23..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** Holds a list of TxnOp instance representing transactional operations. */ -public class TxnBuffer -{ - private final List<TxnOp> _ops = new ArrayList<TxnOp>(); - private static final Logger _log = Logger.getLogger(TxnBuffer.class); - - public TxnBuffer() - { - } - - public void commit(StoreContext context) throws AMQException - { - if (_log.isDebugEnabled()) - { - _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); - } - - if (prepare(context)) - { - for (TxnOp op : _ops) - { - op.commit(context); - } - } - _ops.clear(); - } - - private boolean prepare(StoreContext context) throws AMQException - { - for (int i = 0; i < _ops.size(); i++) - { - TxnOp op = _ops.get(i); - try - { - op.prepare(context); - } - catch (AMQException e) - { - undoPrepare(i); - throw e; - } - catch (RuntimeException e) - { - undoPrepare(i); - throw e; - } - } - return true; - } - - private void undoPrepare(int lastPrepared) - { - //compensate previously prepared ops - for (int j = 0; j < lastPrepared; j++) - { - _ops.get(j).undoPrepare(); - } - } - - - - public void rollback(StoreContext context) throws AMQException - { - for (TxnOp op : _ops) - { - op.rollback(context); - } - _ops.clear(); - } - - public void enlist(TxnOp op) - { - _ops.add(op); - } - - public void cancel(TxnOp op) - { - _ops.remove(op); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java deleted file mode 100644 index 919c078cf0..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnOp.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; - -/** - * This provides the abstraction of an individual operation within a - * transaction. It is used by the TxnBuffer class. - */ -public interface TxnOp -{ - /** - * Do the part of the operation that updates persistent state - */ - public void prepare(StoreContext context) throws AMQException; - /** - * Complete the operation started by prepare. Can now update in - * memory state or make netork transfers. - */ - public void commit(StoreContext context) throws AMQException; - /** - * This is not the same as rollback. Unfortunately the use of an - * in memory reference count as a locking mechanism and a test for - * whether a message should be deleted means that as things are, - * handling an acknowledgement unavoidably alters both memory and - * persistent state on prepare. This is needed to 'compensate' or - * undo the in-memory change if the peristent update of later ops - * fails. - */ - public void undoPrepare(); - /** - * Rolls back the operation. - */ - public void rollback(StoreContext context) throws AMQException; -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index 3b776a62b4..e4a382d275 100644..100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -1,624 +1,62 @@ /* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ package org.apache.qpid.server.virtualhost; -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.logging.messages.VirtualHostMessages; -import org.apache.qpid.server.configuration.ExchangeConfiguration; -import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.connection.ConnectionRegistry; import org.apache.qpid.server.connection.IConnectionRegistry; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.Accessable; -import org.apache.qpid.server.security.access.plugins.SimpleXML; -import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; - -import javax.management.NotCompliantMBeanException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.management.ManagedObject; -public class VirtualHost implements Accessable +public interface VirtualHost { - private static final Logger _logger = Logger.getLogger(VirtualHost.class); - - private final String _name; - - private ConnectionRegistry _connectionRegistry; - - private QueueRegistry _queueRegistry; - - private ExchangeRegistry _exchangeRegistry; - - private ExchangeFactory _exchangeFactory; - - private MessageStore _messageStore; - - protected VirtualHostMBean _virtualHostMBean; - - private AMQBrokerManagerMBean _brokerMBean; - - private AuthenticationManager _authenticationManager; - - private ACLManager _accessManager; - - private final Timer _houseKeepingTimer; - private VirtualHostConfiguration _configuration; - - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - - public IConnectionRegistry getConnectionRegistry() - { - return _connectionRegistry; - } - - public VirtualHostConfiguration getConfiguration() - { - return _configuration; - } - - /** - * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any - * implementaion of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); - } - - public String getObjectInstanceName() - { - return _name.toString(); - } - - public String getName() - { - return _name.toString(); - } - - public VirtualHost getVirtualHost() - { - return VirtualHost.this; - } - - } // End of MBean class - - /** - * Normal Constructor - * - * @param hostConfig - * - * @throws Exception - */ - public VirtualHost(VirtualHostConfiguration hostConfig) throws Exception - { - this(hostConfig, null); - } - - public VirtualHost(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception - { - _configuration = hostConfig; - _name = hostConfig.getName(); - - CurrentActor.get().message(VirtualHostMessages.VHT_1001(_name)); - - if (_name == null || _name.length() == 0) - { - throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); - } - - _virtualHostMBean = new VirtualHostMBean(); - - _connectionRegistry = new ConnectionRegistry(this); - - _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); - - _queueRegistry = new DefaultQueueRegistry(this); - - _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); - - _exchangeRegistry = new DefaultExchangeRegistry(this); - - //Create a temporary RT to store the durable entries from the config file - // so we can replay them in to the real _RT after it has been loaded. - /// This should be removed after the _RT has been fully split from the the TL - - StartupRoutingTable configFileRT = new StartupRoutingTable(); - - _messageStore = configFileRT; - - // This needs to be after the RT has been defined as it creates the default durable exchanges. - _exchangeRegistry.initialise(); - - // We don't need to store the Default queues in the store as we always - // create them first on start up so don't clear them from the startup - // configuration here. This also ensures that we don't attempt to - // perform a createExchange twice with the same details in the - // MessageStore(RoutingTable) as some instances may not like that. - // Derby being one. - // todo this can be removed with the resolution fo QPID-2096 - configFileRT.exchange.clear(); - - initialiseModel(hostConfig); - - //todo REMOVE Work Around for QPID-2096 - // This means that all durable exchanges declared in the configuration - // will not be stored in the MessageStore. - // They will still be created/registered/available on startup for as - // long as they are contained in the configuration. However, when they - // are removed from the configuration they will no longer exist. - // This differs from durable queues as they will be writen to to the - // store. After QPID-2096 has been resolved exchanges will mirror that - // functionality. - configFileRT.exchange.clear(); - - if (store != null) - { - _messageStore = store; - } - else - { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config - // file and write them in to the new routing Table. - for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) - { - _messageStore.createQueue(cqt.queue, cqt.arguments); - } - - for (Exchange exchange : configFileRT.exchange) - { - _messageStore.createExchange(exchange); - } - - for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) - { - _messageStore.bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - } - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); - - _accessManager = ApplicationRegistry.getInstance().getAccessManager(); - _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); - - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _brokerMBean.register(); - initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); - } - - private void initialiseHouseKeeping(long period) - { - /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ - if (period != 0L) - { - class RemoveExpiredMessagesTask extends TimerTask - { - public void run() - { - for (AMQQueue q : _queueRegistry.getQueues()) - { - - try - { - q.checkMessageStatus(); - } - catch (AMQException e) - { - _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); - throw new RuntimeException(e); - } - } - } - } - - _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), - period / 2, - period); - - class ForceChannelClosuresTask extends TimerTask - { - public void run() - { - _connectionRegistry.expireClosedChannels(); - } - } - } - } - - private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception - { - String messageStoreClass = hostConfig.getMessageStoreClass(); - - Class clazz = Class.forName(messageStoreClass); - Object o = clazz.newInstance(); - - if (!(o instanceof MessageStore)) - { - throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + - " does not."); - } - MessageStore messageStore = (MessageStore) o; - messageStore.configure(this, "store", hostConfig); - _messageStore = messageStore; - } - - private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException - { - _logger.debug("Loading configuration for virtualhost: " + config.getName()); - - List exchangeNames = config.getExchanges(); - - for (Object exchangeNameObj : exchangeNames) - { - String exchangeName = String.valueOf(exchangeNameObj); - configureExchange(config.getExchangeConfiguration(exchangeName)); - } - - String[] queueNames = config.getQueueNames(); - - for (Object queueNameObj : queueNames) - { - String queueName = String.valueOf(queueNameObj); - configureQueue(config.getQueueConfiguration(queueName)); - } - } - - private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException - { - AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); - - Exchange exchange; - exchange = _exchangeRegistry.getExchange(exchangeName); - if (exchange == null) - { - - AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); - boolean durable = exchangeConfiguration.getDurable(); - boolean autodelete = exchangeConfiguration.getAutoDelete(); - - Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); - _exchangeRegistry.registerExchange(newExchange); - } - } - - private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException - { - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); - - if (queue.isDurable()) - { - _messageStore.createQueue(queue); - } - - String exchangeName = queueConfiguration.getExchange(); - - Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); - - if (exchange == null) - { - exchange = _exchangeRegistry.getDefaultExchange(); - } - - if (exchange == null) - { - throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); - } - - List routingKeys = queueConfiguration.getRoutingKeys(); - if (routingKeys == null || routingKeys.isEmpty()) - { - routingKeys = Collections.singletonList(queue.getName()); - } - - for (Object routingKeyNameObj : routingKeys) - { - AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); - if (_logger.isInfoEnabled()) - { - _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); - } - queue.bind(exchange, routingKey, null); - } - - if (exchange != _exchangeRegistry.getDefaultExchange()) - { - queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); - } - } - - public String getName() - { - return _name; - } - - public QueueRegistry getQueueRegistry() - { - return _queueRegistry; - } - - public ExchangeRegistry getExchangeRegistry() - { - return _exchangeRegistry; - } - - public ExchangeFactory getExchangeFactory() - { - return _exchangeFactory; - } - - public MessageStore getMessageStore() - { - return _messageStore; - } - - public AuthenticationManager getAuthenticationManager() - { - return _authenticationManager; - } - - public ACLManager getAccessManager() - { - return _accessManager; - } - - public void close() throws Exception - { - - //Stop Connections - _connectionRegistry.close(); - - //Stop the Queues processing - if (_queueRegistry != null) - { - for (AMQQueue queue : _queueRegistry.getQueues()) - { - queue.stop(); - } - } - - //Stop Housekeeping - if (_houseKeepingTimer != null) - { - _houseKeepingTimer.cancel(); - } - - //Close MessageStore - if (_messageStore != null) - { - _messageStore.close(); - } - - CurrentActor.get().message(VirtualHostMessages.VHT_1002()); - } - - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } - - /** - * Temporary Startup RT class to record the creation of persistent queues / exchanges. - * - * - * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. - * This should be removed after the _RT has been fully split from the the TL - */ - private class StartupRoutingTable implements MessageStore - { - public List<Exchange> exchange = new LinkedList<Exchange>(); - public List<CreateQueueTuple> queue = new LinkedList<CreateQueueTuple>(); - public List<CreateBindingTuple> bindings = new LinkedList<CreateBindingTuple>(); - - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception - { - } - - public void close() throws Exception - { - } - - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void createExchange(Exchange exchange) throws AMQException - { - if (exchange.isDurable()) - { - this.exchange.add(exchange); - } - } - - public void removeExchange(Exchange exchange) throws AMQException - { - } - - public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - if (exchange.isDurable() && queue.isDurable()) - { - bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); - } - } - - public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException - { - } - - public void createQueue(AMQQueue queue) throws AMQException - { - createQueue(queue, null); - } - - public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException - { - if (queue.isDurable()) - { - this.queue.add(new CreateQueueTuple(queue, arguments)); - } - } - - public void removeQueue(AMQQueue queue) throws AMQException - { - } - - public void enqueueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void beginTran(StoreContext context) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public void commitTran(StoreContext context) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + IConnectionRegistry getConnectionRegistry(); - public void abortTran(StoreContext context) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + VirtualHostConfiguration getConfiguration(); - public boolean inTran(StoreContext context) - { - return false; //To change body of implemented methods use File | Settings | File Templates. - } + String getName(); - public Long getNewMessageId() - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } + QueueRegistry getQueueRegistry(); - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + ExchangeRegistry getExchangeRegistry(); - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException - { - //To change body of implemented methods use File | Settings | File Templates. - } + ExchangeFactory getExchangeFactory(); - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } + MessageStore getMessageStore(); - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } + TransactionLog getTransactionLog(); - public boolean isPersistent() - { - return false; //To change body of implemented methods use File | Settings | File Templates. - } + DurableConfigurationStore getDurableConfigurationStore(); - private class CreateQueueTuple - { - public AMQQueue queue; - public FieldTable arguments; + AuthenticationManager getAuthenticationManager(); - public CreateQueueTuple(AMQQueue queue, FieldTable arguments) - { - this.queue = queue; - this.arguments = arguments; - } - } + ACLManager getAccessManager(); - private class CreateBindingTuple - { - public AMQQueue queue; - public FieldTable arguments; - public Exchange exchange; - public AMQShortString routingKey; + void close() throws Exception; - public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) - { - this.exchange = exchange; - this.routingKey = routingKey; - this.queue = queue; - arguments = args; - } - } - } + ManagedObject getManagedObject(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java new file mode 100755 index 0000000000..7fa5a26436 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -0,0 +1,340 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.virtualhost; + +import org.apache.qpid.server.store.ConfigurationRecoveryHandler; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.MessageStoreRecoveryHandler; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.store.TransactionLogRecoveryHandler; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.TransactionLogResource; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.AMQException; + +import org.apache.log4j.Logger; + +import java.nio.ByteBuffer; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; + +public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHandler, + ConfigurationRecoveryHandler.QueueRecoveryHandler, + ConfigurationRecoveryHandler.ExchangeRecoveryHandler, + ConfigurationRecoveryHandler.BindingRecoveryHandler, + MessageStoreRecoveryHandler, + MessageStoreRecoveryHandler.StoredMessageRecoveryHandler, + TransactionLogRecoveryHandler, + TransactionLogRecoveryHandler.QueueEntryRecoveryHandler +{ + private static final Logger _logger = Logger.getLogger(VirtualHostConfigRecoveryHandler.class); + + + private final VirtualHost _virtualHost; + + private MessageStoreLogSubject _logSubject; + private List<ProcessAction> _actions; + + private MessageStore _store; + private TransactionLog _transactionLog; + + private final Map<String, Integer> _queueRecoveries = new TreeMap<String, Integer>(); + private Map<Long, ServerMessage> _recoveredMessages = new HashMap<Long, ServerMessage>(); + private Map<Long, StoredMessage> _unusedMessages = new HashMap<Long, StoredMessage>(); + + + + public VirtualHostConfigRecoveryHandler(VirtualHost virtualHost) + { + _virtualHost = virtualHost; + } + + public QueueRecoveryHandler begin(MessageStore store) + { + _logSubject = new MessageStoreLogSubject(_virtualHost,store); + _store = store; + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(null, false)); + + return this; + } + + public void queue(String queueName, String owner, FieldTable arguments) + { + AMQShortString queueNameShortString = new AMQShortString(queueName); + + AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + + if (q == null) + { + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + arguments); + _virtualHost.getQueueRegistry().registerQueue(q); + } + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1004(queueName, true)); + + //Record that we have a queue for recovery + _queueRecoveries.put(queueName, 0); + } + + public ExchangeRecoveryHandler completeQueueRecovery() + { + return this; + } + + public void exchange(String exchangeName, String type, boolean autoDelete) + { + try + { + Exchange exchange; + AMQShortString exchangeNameSS = new AMQShortString(exchangeName); + exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeNameSS); + if (exchange == null) + { + exchange = _virtualHost.getExchangeFactory().createExchange(exchangeNameSS, new AMQShortString(type), true, autoDelete, 0); + _virtualHost.getExchangeRegistry().registerExchange(exchange); + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public BindingRecoveryHandler completeExchangeRecovery() + { + return this; + } + + public StoredMessageRecoveryHandler begin() + { + // TODO - log begin + return this; + } + + public void message(StoredMessage message) + { + ServerMessage serverMessage; + switch(message.getMetaData().getType()) + { + case META_DATA_0_8: + serverMessage = new AMQMessage(message); + break; + case META_DATA_0_10: + serverMessage = new MessageTransferMessage(message, null); + break; + default: + throw new RuntimeException("Unknown message type retreived from store " + message.getMetaData().getClass()); + } + + + _recoveredMessages.put(message.getMessageNumber(), serverMessage); + _unusedMessages.put(message.getMessageNumber(), message); + } + + public void completeMessageRecovery() + { + //TODO - log end + //To change body of implemented methods use File | Settings | File Templates. + } + + public TransactionLogRecoveryHandler.QueueEntryRecoveryHandler begin(TransactionLog log) + { + _transactionLog = log; + return this; + } + + private static final class ProcessAction + { + private final AMQQueue _queue; + private final AMQMessage _message; + + public ProcessAction(AMQQueue queue, AMQMessage message) + { + _queue = queue; + _message = message; + } + + public void process() + { + try + { + _queue.enqueue(_message); + } + catch(AMQException e) + { + throw new RuntimeException(e); + } + } + + } + + public void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf) + { + _actions = new ArrayList<ProcessAction>(); + try + { + QueueRegistry queueRegistry = _virtualHost.getQueueRegistry(); + Exchange exchange = _virtualHost.getExchangeRegistry().getExchange(exchangeName); + AMQQueue queue = queueRegistry.getQueue(new AMQShortString(queueName)); + if (queue == null) + { + _logger.error("Unkown queue: " + queueName + " cannot be bound to exchange: " + + exchange.getName()); + } + else + { + + + FieldTable argumentsFT = null; + if(buf != null) + { + argumentsFT = new FieldTable(org.apache.mina.common.ByteBuffer.wrap(buf),buf.limit()); + } + + _logger.info("Restoring binding: (Exchange: " + exchange.getName() + ", Queue: " + queueName + + ", Routing Key: " + bindingKey + ", Arguments: " + argumentsFT + ")"); + + queue.bind(exchange, bindingKey == null ? null : new AMQShortString(bindingKey), argumentsFT); + + } + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + + } + + public void completeBindingRecovery() + { + //return this; + } + + public void complete() + { + + + } + + public void queueEntry(final String queueName, long messageId) + { + AMQShortString queueNameShortString = new AMQShortString(queueName); + + AMQQueue queue = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + + try + { + if(queue != null) + { + ServerMessage message = _recoveredMessages.get(messageId); + _unusedMessages.remove(messageId); + + if(message != null) + { + + + if (_logger.isDebugEnabled()) + { + _logger.debug("On recovery, delivering " + message.getMessageNumber() + " to " + queue.getName()); + } + + Integer count = _queueRecoveries.get(queueName); + if (count == null) + { + count = 0; + } + + queue.enqueue(message); + + _queueRecoveries.put(queueName, ++count); + } + else + { + _logger.warn("Message id " + messageId + " referenced in log as enqueue in queue " + queue.getName() + " is unknwon, entry will be discarded"); + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + txn.dequeueMessage(queue, messageId); + txn.commitTranAsync(); + } + } + else + { + _logger.warn("Message id " + messageId + " in log references queue " + queueName + " which is not in the configuration, entry will be discarded"); + TransactionLog.Transaction txn = _transactionLog.newTransaction(); + TransactionLogResource mockQueue = + new TransactionLogResource() + { + + public String getResourceName() + { + return queueName; + } + }; + txn.dequeueMessage(mockQueue, messageId); + txn.commitTranAsync(); + } + + } + catch(AMQException e) + { + throw new RuntimeException(e); + } + + + + } + + public void completeQueueEntryRecovery() + { + + for(StoredMessage m : _unusedMessages.values()) + { + _logger.warn("Message id " + m.getMessageNumber() + " in store, but not in any queue - removing...."); + m.remove(); + } + + for(Map.Entry<String,Integer> entry : _queueRecoveries.entrySet()) + { + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1005(entry.getValue(), entry.getKey())); + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(entry.getKey(), true)); + } + + CurrentActor.get().message(_logSubject, TransactionLogMessages.TXN_1006(null, false)); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java new file mode 100644 index 0000000000..c321fdf3e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -0,0 +1,608 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.virtualhost; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.AMQBrokerManagerMBean; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.VirtualHostMessages; +import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.configuration.ExchangeConfiguration; +import org.apache.qpid.server.configuration.QueueConfiguration; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; +import org.apache.qpid.server.connection.ConnectionRegistry; +import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.exchange.DefaultExchangeFactory; +import org.apache.qpid.server.exchange.DefaultExchangeRegistry; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.DefaultQueueRegistry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.ACLManager; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.ConfigurationRecoveryHandler; + +import javax.management.NotCompliantMBeanException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +public class VirtualHostImpl implements Accessable, VirtualHost +{ + private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class); + + private final String _name; + + private ConnectionRegistry _connectionRegistry; + + private QueueRegistry _queueRegistry; + + private ExchangeRegistry _exchangeRegistry; + + private ExchangeFactory _exchangeFactory; + + private MessageStore _messageStore; + + protected VirtualHostMBean _virtualHostMBean; + + private AMQBrokerManagerMBean _brokerMBean; + + private AuthenticationManager _authenticationManager; + + private ACLManager _accessManager; + + private final Timer _houseKeepingTimer; + private VirtualHostConfiguration _configuration; + private DurableConfigurationStore _durableConfigurationStore; + + public void setAccessableName(String name) + { + _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" + + name + ") ignored remains :" + getAccessableName()); + } + + public String getAccessableName() + { + return _name; + } + + public IConnectionRegistry getConnectionRegistry() + { + return _connectionRegistry; + } + + public VirtualHostConfiguration getConfiguration() + { + return _configuration; + } + + /** + * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any + * implementaion of an Exchange MBean should extend this class. + */ + public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost + { + public VirtualHostMBean() throws NotCompliantMBeanException + { + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, ManagedVirtualHost.VERSION); + } + + public String getObjectInstanceName() + { + return _name.toString(); + } + + public String getName() + { + return _name.toString(); + } + + public VirtualHostImpl getVirtualHost() + { + return VirtualHostImpl.this; + } + + } // End of MBean class + + /** + * Normal Constructor + * + * @param hostConfig + * + * @throws Exception + */ + public VirtualHostImpl(VirtualHostConfiguration hostConfig) throws Exception + { + this(hostConfig, null); + } + + public VirtualHostImpl(VirtualHostConfiguration hostConfig, MessageStore store) throws Exception + { + _configuration = hostConfig; + _name = hostConfig.getName(); + + CurrentActor.get().message(VirtualHostMessages.VHT_1001(_name)); + + if (_name == null || _name.length() == 0) + { + throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); + } + + _virtualHostMBean = new VirtualHostMBean(); + + _connectionRegistry = new ConnectionRegistry(this); + + _houseKeepingTimer = new Timer("Queue-housekeeping-" + _name, true); + + _queueRegistry = new DefaultQueueRegistry(this); + + _exchangeFactory = new DefaultExchangeFactory(this); + _exchangeFactory.initialise(hostConfig); + + _exchangeRegistry = new DefaultExchangeRegistry(this); + + //Create a temporary RT to store the durable entries from the config file + // so we can replay them in to the real _RT after it has been loaded. + /// This should be removed after the _RT has been fully split from the the TL + + StartupRoutingTable configFileRT = new StartupRoutingTable(); + + _durableConfigurationStore = configFileRT; + + // This needs to be after the RT has been defined as it creates the default durable exchanges. + _exchangeRegistry.initialise(); + + // We don't need to store the Default queues in the store as we always + // create them first on start up so don't clear them from the startup + // configuration here. This also ensures that we don't attempt to + // perform a createExchange twice with the same details in the + // MessageStore(RoutingTable) as some instances may not like that. + // Derby being one. + // todo this can be removed with the resolution fo QPID-2096 + configFileRT.exchange.clear(); + + initialiseModel(hostConfig); + + //todo REMOVE Work Around for QPID-2096 + // This means that all durable exchanges declared in the configuration + // will not be stored in the MessageStore. + // They will still be created/registered/available on startup for as + // long as they are contained in the configuration. However, when they + // are removed from the configuration they will no longer exist. + // This differs from durable queues as they will be writen to to the + // store. After QPID-2096 has been resolved exchanges will mirror that + // functionality. + configFileRT.exchange.clear(); + + if (store != null) + { + _messageStore = store; + _durableConfigurationStore = store; + } + else + { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + initialiseMessageStore(hostConfig); + } + + //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config + // file and write them in to the new routing Table. + for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) + { + getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments); + } + + for (Exchange exchange : configFileRT.exchange) + { + getDurableConfigurationStore().createExchange(exchange); + } + + for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) + { + getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); + } + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); + + _accessManager = ApplicationRegistry.getInstance().getAccessManager(); + _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); + + _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); + _brokerMBean.register(); + initialiseHouseKeeping(hostConfig.getHousekeepingExpiredMessageCheckPeriod()); + } + + private void initialiseHouseKeeping(long period) + { + /* add a timer task to iterate over queues, cleaning expired messages from queues with no consumers */ + if (period != 0L) + { + class RemoveExpiredMessagesTask extends TimerTask + { + public void run() + { + for (AMQQueue q : _queueRegistry.getQueues()) + { + + try + { + q.checkMessageStatus(); + } + catch (AMQException e) + { + _logger.error("Exception in housekeeping for queue: " + q.getName().toString(), e); + throw new RuntimeException(e); + } + } + } + } + + _houseKeepingTimer.scheduleAtFixedRate(new RemoveExpiredMessagesTask(), + period / 2, + period); + + class ForceChannelClosuresTask extends TimerTask + { + public void run() + { + _connectionRegistry.expireClosedChannels(); + } + } + } + } + + private void initialiseMessageStore(VirtualHostConfiguration hostConfig) throws Exception + { + String messageStoreClass = hostConfig.getMessageStoreClass(); + + Class clazz = Class.forName(messageStoreClass); + Object o = clazz.newInstance(); + + if (!(o instanceof MessageStore)) + { + throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz + + " does not."); + } + MessageStore messageStore = (MessageStore) o; + VirtualHostConfigRecoveryHandler recoveryHandler = new VirtualHostConfigRecoveryHandler(this); + + MessageStoreLogSubject storeLogSubject = new MessageStoreLogSubject(this, messageStore); + + messageStore.configureConfigStore(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + + messageStore.configureMessageStore(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + messageStore.configureTransactionLog(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + + _messageStore = messageStore; + _durableConfigurationStore = messageStore; + } + + private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException + { + _logger.debug("Loading configuration for virtualhost: " + config.getName()); + + List exchangeNames = config.getExchanges(); + + for (Object exchangeNameObj : exchangeNames) + { + String exchangeName = String.valueOf(exchangeNameObj); + configureExchange(config.getExchangeConfiguration(exchangeName)); + } + + String[] queueNames = config.getQueueNames(); + + for (Object queueNameObj : queueNames) + { + String queueName = String.valueOf(queueNameObj); + configureQueue(config.getQueueConfiguration(queueName)); + } + } + + private void configureExchange(ExchangeConfiguration exchangeConfiguration) throws AMQException + { + AMQShortString exchangeName = new AMQShortString(exchangeConfiguration.getName()); + + Exchange exchange; + exchange = _exchangeRegistry.getExchange(exchangeName); + if (exchange == null) + { + + AMQShortString type = new AMQShortString(exchangeConfiguration.getType()); + boolean durable = exchangeConfiguration.getDurable(); + boolean autodelete = exchangeConfiguration.getAutoDelete(); + + Exchange newExchange = _exchangeFactory.createExchange(exchangeName, type, durable, autodelete, 0); + _exchangeRegistry.registerExchange(newExchange); + } + } + + private void configureQueue(QueueConfiguration queueConfiguration) throws AMQException, ConfigurationException + { + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueConfiguration, this); + + if (queue.isDurable()) + { + getDurableConfigurationStore().createQueue(queue); + } + + String exchangeName = queueConfiguration.getExchange(); + + Exchange exchange = _exchangeRegistry.getExchange(exchangeName == null ? null : new AMQShortString(exchangeName)); + + if (exchange == null) + { + exchange = _exchangeRegistry.getDefaultExchange(); + } + + if (exchange == null) + { + throw new ConfigurationException("Attempt to bind queue to unknown exchange:" + exchangeName); + } + + List routingKeys = queueConfiguration.getRoutingKeys(); + if (routingKeys == null || routingKeys.isEmpty()) + { + routingKeys = Collections.singletonList(queue.getName()); + } + + for (Object routingKeyNameObj : routingKeys) + { + AMQShortString routingKey = new AMQShortString(String.valueOf(routingKeyNameObj)); + if (_logger.isInfoEnabled()) + { + _logger.info("Binding queue:" + queue + " with routing key '" + routingKey + "' to exchange:" + this); + } + queue.bind(exchange, routingKey, null); + } + + if (exchange != _exchangeRegistry.getDefaultExchange()) + { + queue.bind(_exchangeRegistry.getDefaultExchange(), queue.getName(), null); + } + } + + public String getName() + { + return _name; + } + + public QueueRegistry getQueueRegistry() + { + return _queueRegistry; + } + + public ExchangeRegistry getExchangeRegistry() + { + return _exchangeRegistry; + } + + public ExchangeFactory getExchangeFactory() + { + return _exchangeFactory; + } + + public MessageStore getMessageStore() + { + return _messageStore; + } + + public TransactionLog getTransactionLog() + { + return _messageStore; + } + + public DurableConfigurationStore getDurableConfigurationStore() + { + return _durableConfigurationStore; + } + + public AuthenticationManager getAuthenticationManager() + { + return _authenticationManager; + } + + public ACLManager getAccessManager() + { + return _accessManager; + } + + public void close() throws Exception + { + + //Stop Connections + _connectionRegistry.close(); + + //Stop the Queues processing + if (_queueRegistry != null) + { + for (AMQQueue queue : _queueRegistry.getQueues()) + { + queue.stop(); + } + } + + //Stop Housekeeping + if (_houseKeepingTimer != null) + { + _houseKeepingTimer.cancel(); + } + + //Close MessageStore + if (_messageStore != null) + { + _messageStore.close(); + } + + CurrentActor.get().message(VirtualHostMessages.VHT_1002()); + } + + public ManagedObject getBrokerMBean() + { + return _brokerMBean; + } + + public ManagedObject getManagedObject() + { + return _virtualHostMBean; + } + + /** + * Temporary Startup RT class to record the creation of persistent queues / exchanges. + * + * + * This is so we can replay the creation of queues/exchanges in to the real _RT after it has been loaded. + * This should be removed after the _RT has been fully split from the the TL + */ + private class StartupRoutingTable implements DurableConfigurationStore + { + public List<Exchange> exchange = new LinkedList<Exchange>(); + public List<CreateQueueTuple> queue = new LinkedList<CreateQueueTuple>(); + public List<CreateBindingTuple> bindings = new LinkedList<CreateBindingTuple>(); + + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + { + } + + public void close() throws Exception + { + } + + public void removeMessage(Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void createExchange(Exchange exchange) throws AMQException + { + if (exchange.isDurable()) + { + this.exchange.add(exchange); + } + } + + public void removeExchange(Exchange exchange) throws AMQException + { + } + + public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + if (exchange.isDurable() && queue.isDurable()) + { + bindings.add(new CreateBindingTuple(exchange, routingKey, queue, args)); + } + } + + public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException + { + } + + public void createQueue(AMQQueue queue) throws AMQException + { + createQueue(queue, null); + } + + public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException + { + if (queue.isDurable()) + { + this.queue.add(new CreateQueueTuple(queue, arguments)); + } + } + + public void removeQueue(AMQQueue queue) throws AMQException + { + } + + + private class CreateQueueTuple + { + public AMQQueue queue; + public FieldTable arguments; + + public CreateQueueTuple(AMQQueue queue, FieldTable arguments) + { + this.queue = queue; + this.arguments = arguments; + } + } + + private class CreateBindingTuple + { + public AMQQueue queue; + public FieldTable arguments; + public Exchange exchange; + public AMQShortString routingKey; + + public CreateBindingTuple(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) + { + this.exchange = exchange; + this.routingKey = routingKey; + this.queue = queue; + arguments = args; + } + } + } + + @Override + public String toString() + { + return _name; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index 5543adbeb5..b86e0d0baf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.virtualhost;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
import java.util.ArrayList;
import java.util.Collection;
@@ -31,7 +30,7 @@ import java.util.concurrent.ConcurrentHashMap; public class VirtualHostRegistry
{
- private final Map<String, VirtualHost> _registry = new ConcurrentHashMap<String,VirtualHost>();
+ private final Map<String, VirtualHost> _registry = new ConcurrentHashMap<String, VirtualHost>();
private String _defaultVirtualHostName;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java index 0869d9a497..ef3599bdc8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Copy.java @@ -14,14 +14,16 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.tools.messagestore.commands; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.LocalTransaction; public class Copy extends Move { @@ -49,7 +51,9 @@ public class Copy extends Move protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) { - fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), _storeContext); + ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); + fromQueue.copyMessagesToAnotherQueue(start, end, toQueue.getName().toString(), txn); + txn.commit(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java index 731f6140f9..a7d58dc6dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Dump.java @@ -21,16 +21,13 @@ package org.apache.qpid.tools.messagestore.commands; import org.apache.commons.codec.binary.Hex; -import org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.AMQMessage; import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.tools.utils.Console; import java.io.UnsupportedEncodingException; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -100,7 +97,7 @@ public class Dump extends Show for (QueueEntry entry : messages) { - AMQMessage msg = entry.getMessage(); + ServerMessage msg = entry.getMessage(); if (!includeMsg(msg, msgids)) { continue; @@ -112,7 +109,7 @@ public class Dump extends Show // Show general message information hex.add(Show.Columns.ID.name()); - ascii.add(msg.getMessageId().toString()); + ascii.add(msg.getMessageNumber().toString()); hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); @@ -136,10 +133,10 @@ public class Dump extends Show hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); - Iterator bodies = msg.getContentBodyIterator(); - if (bodies.hasNext()) - { + final int messageSize = (int) msg.getSize(); + if (messageSize != 0) + { hex.add("Hex"); hex.add(Console.ROW_DIVIDER); @@ -147,14 +144,19 @@ public class Dump extends Show ascii.add("ASCII"); ascii.add(Console.ROW_DIVIDER); - while (bodies.hasNext()) + java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(64 * 1024); + + int position = 0; + + while(position < messageSize) { - ContentChunk chunk = (ContentChunk) bodies.next(); + position += msg.getContent(buf, position); + buf.flip(); //Duplicate so we don't destroy original data :) - ByteBuffer hexBuffer = chunk.getData().duplicate(); + java.nio.ByteBuffer hexBuffer = buf; - ByteBuffer charBuffer = hexBuffer.duplicate(); + java.nio.ByteBuffer charBuffer = hexBuffer.duplicate(); Hex hexencoder = new Hex(); @@ -232,6 +234,7 @@ public class Dump extends Show ascii.add(asciiLine); } + buf.clear(); } } else @@ -252,7 +255,7 @@ public class Dump extends Show return display; } - private void addShowInformation(List<String> column1, List<String> column2, AMQMessage msg, + 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>(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java index df8b59ec19..ab8e781df5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/List.java @@ -14,9 +14,9 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.tools.messagestore.commands; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java index a8dd58ca83..6a5e2a6025 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Move.java @@ -14,17 +14,17 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.tools.messagestore.commands; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.StoreContext; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.tools.messagestore.MessageStoreTool; import java.util.LinkedList; @@ -33,12 +33,6 @@ import java.util.List; public class Move extends AbstractCommand { - /** - * Since the Coopy command is not associated with a real channel we can safely create our own store context - * for use in the few methods that require one. - */ - protected StoreContext _storeContext = new StoreContext(); - public Move(MessageStoreTool tool) { super(tool); @@ -172,7 +166,7 @@ public class Move extends AbstractCommand { for (QueueEntry msg : messages) { - ids.add(msg.getMessage().getMessageId()); + ids.add(msg.getMessage().getMessageNumber()); } } } @@ -201,6 +195,8 @@ public class Move extends AbstractCommand protected void doCommand(AMQQueue fromQueue, long start, long id, AMQQueue toQueue) { - fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), _storeContext); + ServerTransaction txn = new LocalTransaction(fromQueue.getVirtualHost().getTransactionLog()); + fromQueue.moveMessagesToAnotherQueue(start, id, toQueue.getName().toString(), txn); + txn.commit(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java index 5e99997863..8df4afa2db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Purge.java @@ -62,6 +62,6 @@ public class Purge extends Move protected void doCommand(AMQQueue fromQueue, long start, long end, AMQQueue toQueue) { - fromQueue.removeMessagesFromQueue(start, end, _storeContext); + fromQueue.removeMessagesFromQueue(start, end); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java index 2fa017fc64..4fd4999b19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/messagestore/commands/Show.java @@ -25,10 +25,10 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.QueueEntryImpl; +import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.tools.utils.Console; @@ -171,7 +171,7 @@ public class Show extends AbstractCommand // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getEncoding(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getExpiration(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders(); -// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageId(); +// ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getMessageNumber(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPriority(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getPropertyFlags(); // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getReplyTo(); @@ -182,14 +182,14 @@ public class Show extends AbstractCommand // //Print out all the property names // ((BasicContentHeaderProperties)msg.getContentHeaderBody().properties).getHeaders().getPropertyNames(); // -// msg.getMessageId(); +// msg.getMessageNumber(); // msg.getSize(); // msg.getArrivalTime(); // msg.getDeliveredSubscription(); // msg.getDeliveredToConsumer(); // msg.getMessageHandle(); -// msg.getMessageId(); +// msg.getMessageNumber(); // msg.getMessagePublishInfo(); // msg.getPublisher(); @@ -337,30 +337,24 @@ public class Show extends AbstractCommand //Add create the table of data for (QueueEntry entry : messages) { - AMQMessage msg = entry.getMessage(); + ServerMessage msg = entry.getMessage(); if (!includeMsg(msg, msgids)) { continue; } - id.add(msg.getMessageId().toString()); + id.add(msg.getMessageNumber().toString()); size.add("" + msg.getSize()); arrival.add("" + msg.getArrivalTime()); - try - { - ispersitent.add(msg.isPersistent() ? "true" : "false"); - } - catch (AMQException e) - { - ispersitent.add("n/a"); - } + ispersitent.add(msg.isPersistent() ? "true" : "false"); + - isredelivered.add(msg.isRedelivered() ? "true" : "false"); + isredelivered.add(entry.isRedelivered() ? "true" : "false"); - isdelivered.add(msg.getDeliveredToConsumer() ? "true" : "false"); + isdelivered.add(entry.getDeliveredToConsumer() ? "true" : "false"); // msg.getMessageHandle(); @@ -368,7 +362,10 @@ public class Show extends AbstractCommand try { - headers = ((BasicContentHeaderProperties) msg.getContentHeaderBody().properties); + if(msg instanceof AMQMessage) + { + headers = ((BasicContentHeaderProperties) ((AMQMessage)msg).getContentHeaderBody().properties); + } } catch (AMQException e) { @@ -417,7 +414,11 @@ public class Show extends AbstractCommand MessagePublishInfo info = null; try { - info = msg.getMessagePublishInfo(); + if(msg instanceof AMQMessage) + { + info = ((AMQMessage)msg).getMessagePublishInfo(); + } + } catch (AMQException e) { @@ -457,14 +458,14 @@ public class Show extends AbstractCommand return data; } - protected boolean includeMsg(AMQMessage msg, List<Long> msgids) + protected boolean includeMsg(ServerMessage msg, List<Long> msgids) { if (msgids == null) { return true; } - Long msgid = msg.getMessageId(); + Long msgid = msg.getMessageNumber(); boolean found = false; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java index e3889162ad..3cdb9c0c2d 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java @@ -27,6 +27,7 @@ import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; public class AMQBrokerManagerMBeanTest extends TestCase @@ -46,7 +47,7 @@ public class AMQBrokerManagerMBeanTest extends TestCase assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null); - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) _vHost.getManagedObject()); + ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); mbean.createNewExchange(exchange1, "direct", false); mbean.createNewExchange(exchange2, "topic", false); mbean.createNewExchange(exchange3, "headers", false); @@ -68,7 +69,7 @@ public class AMQBrokerManagerMBeanTest extends TestCase { String queueName = "testQueue_" + System.currentTimeMillis(); - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) _vHost.getManagedObject()); + ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java index 105056fe3d..d2408ba21f 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java @@ -22,23 +22,22 @@ package org.apache.qpid.server; import junit.framework.TestCase; import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl; -import org.apache.qpid.server.queue.MockQueueEntry; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.SimpleQueueEntryList; import org.apache.qpid.server.queue.MockAMQMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MockAMQQueue; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.queue.QueueEntryIterator; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.MockSubscription; +import org.apache.qpid.server.store.MemoryMessageStore; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.AMQException; import java.util.Map; import java.util.LinkedHashMap; import java.util.LinkedList; -import java.util.Iterator; /** * QPID-1385 : Race condition between added to unacked map and resending due to a rollback. @@ -63,6 +62,7 @@ public class ExtractResendAndRequeueTest extends TestCase UnacknowledgedMessageMapImpl _unacknowledgedMessageMap; private static final int INITIAL_MSG_COUNT = 10; private AMQQueue _queue = new MockAMQQueue(getName()); + private MessageStore _messageStore = new MemoryMessageStore(); private LinkedList<QueueEntry> _referenceList = new LinkedList<QueueEntry>(); @Override @@ -89,7 +89,7 @@ public class ExtractResendAndRequeueTest extends TestCase while(queueEntries.advance()) { QueueEntry entry = queueEntries.getNode(); - _unacknowledgedMessageMap.add(entry.getMessage().getMessageId(), entry); + _unacknowledgedMessageMap.add(entry.getMessage().getMessageNumber(), entry); // Store the entry for future inspection _referenceList.add(entry); @@ -137,7 +137,7 @@ public class ExtractResendAndRequeueTest extends TestCase // requeueIfUnabletoResend doesn't matter here. _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, true, new StoreContext())); + msgToResend, true, _messageStore)); assertEquals("Message count for resend not correct.", INITIAL_MSG_COUNT, msgToResend.size()); assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size()); @@ -166,7 +166,7 @@ public class ExtractResendAndRequeueTest extends TestCase // requeueIfUnabletoResend doesn't matter here. _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, true, new StoreContext())); + msgToResend, true, _messageStore)); assertEquals("Message count for resend not correct.", 0, msgToResend.size()); assertEquals("Message count for requeue not correct.", INITIAL_MSG_COUNT, msgToRequeue.size()); @@ -187,7 +187,7 @@ public class ExtractResendAndRequeueTest extends TestCase // requeueIfUnabletoResend = true so all messages should go to msgToRequeue _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, true, new StoreContext())); + msgToResend, true, _messageStore)); assertEquals("Message count for resend not correct.", 0, msgToResend.size()); assertEquals("Message count for requeue not correct.", INITIAL_MSG_COUNT, msgToRequeue.size()); @@ -208,7 +208,7 @@ public class ExtractResendAndRequeueTest extends TestCase // requeueIfUnabletoResend = false so all messages should be dropped all maps should be empty _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, false, new StoreContext())); + msgToResend, false, _messageStore)); assertEquals("Message count for resend not correct.", 0, msgToResend.size()); assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size()); @@ -240,7 +240,7 @@ public class ExtractResendAndRequeueTest extends TestCase // requeueIfUnabletoResend : value doesn't matter here as queue has been deleted _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue, - msgToResend, false, new StoreContext())); + msgToResend, false, _messageStore)); assertEquals("Message count for resend not correct.", 0, msgToResend.size()); assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size()); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java deleted file mode 100644 index 06d6b6de8b..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.ack; - -import junit.framework.TestCase; - -import org.apache.commons.configuration.PropertiesConfiguration; -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.RequiredDeliveryException; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.queue.AMQMessageHandle; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.store.TestMemoryMessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; - -import java.util.*; - -public class TxAckTest extends TestCase -{ - private Scenario individual; - private Scenario multiple; - private Scenario combined; - - protected void setUp() throws Exception - { - super.setUp(); - - - // Highlight that this test will cause the creation of an AR - ApplicationRegistry.getInstance(); - - //ack only 5th msg - individual = new Scenario(10, Arrays.asList(5l), Arrays.asList(1l, 2l, 3l, 4l, 6l, 7l, 8l, 9l, 10l)); - individual.update(5, false); - - //ack all up to and including 5th msg - multiple = new Scenario(10, Arrays.asList(1l, 2l, 3l, 4l, 5l), Arrays.asList(6l, 7l, 8l, 9l, 10l)); - multiple.update(5, true); - - //leave only 8th and 9th unacked - combined = new Scenario(10, Arrays.asList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 10l), Arrays.asList(8l, 9l)); - combined.update(3, false); - combined.update(5, true); - combined.update(7, true); - combined.update(2, true);//should be ignored - combined.update(1, false);//should be ignored - combined.update(10, false); - } - - @Override - protected void tearDown() throws Exception - { - individual.stop(); - multiple.stop(); - combined.stop(); - - // Ensure we close the AR we created - ApplicationRegistry.remove(); - super.tearDown(); - } - - public void testPrepare() throws AMQException - { - individual.prepare(); - multiple.prepare(); - combined.prepare(); - } - - public void testUndoPrepare() throws AMQException - { - individual.undoPrepare(); - multiple.undoPrepare(); - combined.undoPrepare(); - } - - public void testCommit() throws AMQException - { - individual.commit(); - multiple.commit(); - combined.commit(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(TxAckTest.class); - } - - private class Scenario - { - private final UnacknowledgedMessageMap _map = new UnacknowledgedMessageMapImpl(5000); - private final TxAck _op = new TxAck(_map); - private final List<Long> _acked; - private final List<Long> _unacked; - private StoreContext _storeContext = new StoreContext(); - private AMQQueue _queue; - - Scenario(int messageCount, List<Long> acked, List<Long> unacked) throws Exception - { - TransactionalContext txnContext = new NonTransactionalContext(new TestMemoryMessageStore(), - _storeContext, null, - new LinkedList<RequiredDeliveryException>() - ); - - VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next(); - - _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("test"), false, null, false, - virtualHost, null); - - for (int i = 0; i < messageCount; i++) - { - long deliveryTag = i + 1; - - MessagePublishInfo info = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return null; - } - - public void setExchange(AMQShortString exchange) - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean isImmediate() - { - return false; - } - - public boolean isMandatory() - { - return false; - } - - public AMQShortString getRoutingKey() - { - return null; - } - }; - - TestMessage message = new TestMessage(deliveryTag, i, info, txnContext.getStoreContext()); - _map.add(deliveryTag, _queue.enqueue(new StoreContext(), message)); - } - _acked = acked; - _unacked = unacked; - } - - void update(long deliverytag, boolean multiple) - { - _op.update(deliverytag, multiple); - } - - private void assertCount(List<Long> tags, int expected) - { - for (long tag : tags) - { - QueueEntry u = _map.get(tag); - assertTrue("Message not found for tag " + tag, u != null); - ((TestMessage) u.getMessage()).assertCountEquals(expected); - } - } - - void prepare() throws AMQException - { - _op.consolidate(); - _op.prepare(_storeContext); - - assertCount(_acked, -1); - assertCount(_unacked, 0); - - } - - void undoPrepare() - { - _op.consolidate(); - _op.undoPrepare(); - - assertCount(_acked, 1); - assertCount(_unacked, 0); - } - - void commit() - { - _op.consolidate(); - _op.commit(_storeContext); - - //check acked messages are removed from map - Set<Long> keys = new HashSet<Long>(_map.getDeliveryTags()); - keys.retainAll(_acked); - assertTrue("Expected messages with following tags to have been removed from map: " + keys, keys.isEmpty()); - //check unacked messages are still in map - keys = new HashSet<Long>(_unacked); - keys.removeAll(_map.getDeliveryTags()); - assertTrue("Expected messages with following tags to still be in map: " + keys, keys.isEmpty()); - } - - public void stop() - { - _queue.stop(); - } - } - - private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody) - { - final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, - null, - false); - try - { - amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(), - publishBody, - new ContentHeaderBody() - { - public int getSize() - { - return 1; - } - }); - } - catch (AMQException e) - { - // won't happen - } - - - return amqMessageHandle; - } - - - private class TestMessage extends AMQMessage - { - private final long _tag; - private int _count; - - TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext) - throws AMQException - { - super(createMessageHandle(messageId, publishBody), storeContext, publishBody); - _tag = tag; - } - - - public boolean incrementReference() - { - _count++; - return true; - } - - public void decrementReference(StoreContext context) - { - _count--; - } - - void assertCountEquals(int expected) - { - assertEquals("Wrong count for message with tag " + _tag, expected, _count); - } - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java index c5f291a0cb..5bd739c0af 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -27,6 +27,7 @@ import java.io.RandomAccessFile; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Collections; import junit.framework.TestCase; @@ -482,12 +483,17 @@ public class ServerConfigurationTest extends TestCase { // Check default ServerConfiguration serverConfig = new ServerConfiguration(_config); - assertEquals(5672, serverConfig.getPort()); + assertNotNull(serverConfig.getPorts()); + assertEquals(1, serverConfig.getPorts().size()); + assertEquals(5672, serverConfig.getPorts().get(0)); + // Check value we set - _config.setProperty("connector.port", 10); + _config.setProperty("connector.port", "10"); serverConfig = new ServerConfiguration(_config); - assertEquals(10, serverConfig.getPort()); + assertNotNull(serverConfig.getPorts()); + assertEquals(1, serverConfig.getPorts().size()); + assertEquals("10", serverConfig.getPorts().get(0)); } public void testGetBind() throws ConfigurationException @@ -723,7 +729,9 @@ public class ServerConfigurationTest extends TestCase ServerConfiguration config = new ServerConfiguration(mainFile.getAbsoluteFile()); assertEquals(4235, config.getSSLPort()); // From first file, not // overriden by second - assertEquals(2342, config.getPort()); // From the first file, not + assertNotNull(config.getPorts()); + assertEquals(1, config.getPorts().size()); + assertEquals("2342", config.getPorts().get(0)); // From the first file, not // present in the second assertEquals(true, config.getQpidNIO()); // From the second file, not // present in the first @@ -967,7 +975,7 @@ public class ServerConfigurationTest extends TestCase out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); out.write("</firewall>\n"); out.close(); - + reg.getConfiguration().reparseConfigFile(); assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost)); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java index 5d3b4e681a..b65020395c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java @@ -14,21 +14,20 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. - * + * under the License. + * */ package org.apache.qpid.server.configuration; import junit.framework.TestCase; -import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.queue.AMQPriorityQueue; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; public class VirtualHostConfigurationTest extends TestCase { @@ -55,50 +54,50 @@ public class VirtualHostConfigurationTest extends TestCase super.tearDown(); } - + public void testQueuePriority() throws Exception { // Set up queue with 5 priorities - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", + configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "atest"); - configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", + configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.atest.priorities", + configXml.addProperty("virtualhost.test.queues.queue.atest.priorities", "5"); // Set up queue with JMS style priorities - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", + configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "ptest"); - configXml.addProperty("virtualhost.test.queues.queue.ptest(-1).exchange", + configXml.addProperty("virtualhost.test.queues.queue.ptest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.ptest.priority", + configXml.addProperty("virtualhost.test.queues.queue.ptest.priority", "true"); - + // Set up queue with no priorities - configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", + configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "ntest"); - configXml.addProperty("virtualhost.test.queues.queue.ntest(-1).exchange", + configXml.addProperty("virtualhost.test.queues.queue.ntest(-1).exchange", "amq.direct"); - configXml.addProperty("virtualhost.test.queues.queue.ntest.priority", + configXml.addProperty("virtualhost.test.queues.queue.ntest.priority", "false"); - - VirtualHost vhost = new VirtualHost(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test"))); - + + VirtualHost vhost = new VirtualHostImpl(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test"))); + // Check that atest was a priority queue with 5 priorities AMQQueue atest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest")); assertTrue(atest instanceof AMQPriorityQueue); assertEquals(5, ((AMQPriorityQueue) atest).getPriorities()); - + // Check that ptest was a priority queue with 10 priorities AMQQueue ptest = vhost.getQueueRegistry().getQueue(new AMQShortString("ptest")); assertTrue(ptest instanceof AMQPriorityQueue); assertEquals(10, ((AMQPriorityQueue) ptest).getPriorities()); - + // Check that ntest wasn't a priority queue AMQQueue ntest = vhost.getQueueRegistry().getQueue(new AMQShortString("ntest")); assertFalse(ntest instanceof AMQPriorityQueue); } - + public void testQueueAlerts() throws Exception { // Set up queue with 5 priorities @@ -106,7 +105,7 @@ public class VirtualHostConfigurationTest extends TestCase configXml.addProperty("virtualhost.test.queues.maximumQueueDepth", "1"); configXml.addProperty("virtualhost.test.queues.maximumMessageSize", "2"); configXml.addProperty("virtualhost.test.queues.maximumMessageAge", "3"); - + configXml.addProperty("virtualhost.test.queues(-1).queue(1).name(1)", "atest"); configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", "amq.direct"); configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumQueueDepth", "4"); @@ -114,21 +113,21 @@ public class VirtualHostConfigurationTest extends TestCase configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageAge", "6"); configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "btest"); - - VirtualHost vhost = new VirtualHost(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test"))); - + + VirtualHost vhost = new VirtualHostImpl(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test"))); + // Check specifically configured values AMQQueue aTest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest")); assertEquals(4, aTest.getMaximumQueueDepth()); assertEquals(5, aTest.getMaximumMessageSize()); assertEquals(6, aTest.getMaximumMessageAge()); - - // Check default values + + // Check default values AMQQueue bTest = vhost.getQueueRegistry().getQueue(new AMQShortString("btest")); assertEquals(1, bTest.getMaximumQueueDepth()); assertEquals(2, bTest.getMaximumMessageSize()); assertEquals(3, bTest.getMaximumMessageAge()); - + } - + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java index f8dd266bd2..e26b5b048c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java @@ -27,18 +27,18 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.queue.*; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.SkeletonMessageStore; import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.RequiredDeliveryException; -import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.log4j.Logger; import java.util.*; +import java.util.concurrent.atomic.AtomicLong; public class AbstractHeadersExchangeTestBase extends TestCase { @@ -52,10 +52,6 @@ public class AbstractHeadersExchangeTestBase extends TestCase */ private MessageStore _store = new MemoryMessageStore(); - private StoreContext _storeContext = new StoreContext(); - - private MessageHandleFactory _handleFactory = new MessageHandleFactory(); - private int count; public void testDoNothing() @@ -91,14 +87,18 @@ public class AbstractHeadersExchangeTestBase extends TestCase } - protected void route(Message m) throws AMQException + protected int route(Message m) throws AMQException { + m.getIncomingMessage().headersReceived(); m.route(exchange); - m.getIncomingMessage().routingComplete(_store, _handleFactory); if(m.getIncomingMessage().allContentReceived()) { - m.getIncomingMessage().deliverToQueues(); + for(AMQQueue q : m.getIncomingMessage().getDestinationQueues()) + { + q.enqueue(m); + } } + return m.getIncomingMessage().getDestinationQueues().size(); } protected void routeAndTest(Message m, TestQueue... expected) throws AMQException @@ -118,10 +118,8 @@ public class AbstractHeadersExchangeTestBase extends TestCase protected void routeAndTest(Message m, boolean expectReturn, List<TestQueue> expected) throws AMQException { - try - { - route(m); - assertFalse("Expected "+m+" to be returned due to manadatory flag, and lack of routing",expectReturn); + int queueCount = route(m); + for (TestQueue q : queues) { if (expected.contains(q)) @@ -135,12 +133,11 @@ public class AbstractHeadersExchangeTestBase extends TestCase //assert !m.isInQueue(q) : "Did not expect " + m + " to be delivered to " + q; } } - } - catch (NoRouteException ex) - { - assertTrue("Expected "+m+" not to be returned",expectReturn); - } + if(expectReturn) + { + assertEquals("Expected "+m+" to be returned due to manadatory flag, and lack of routing",0, queueCount); + } } @@ -242,6 +239,11 @@ public class AbstractHeadersExchangeTestBase extends TestCase { final List<HeadersExchangeTest.Message> messages = new ArrayList<HeadersExchangeTest.Message>(); + public String toString() + { + return getName().toString(); + } + public TestQueue(AMQShortString name) throws AMQException { super(name, false, new AMQShortString("test"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test")); @@ -256,9 +258,9 @@ public class AbstractHeadersExchangeTestBase extends TestCase * @throws AMQException */ @Override - public QueueEntry enqueue(StoreContext context, AMQMessage msg) throws AMQException + public QueueEntry enqueue(ServerMessage msg) throws AMQException { - messages.add( new HeadersExchangeTest.Message(msg)); + messages.add( new HeadersExchangeTest.Message((AMQMessage) msg)); return new QueueEntry() { @@ -317,6 +319,11 @@ public class AbstractHeadersExchangeTestBase extends TestCase return false; //To change body of implemented methods use File | Settings | File Templates. } + public boolean isAcquiredBy(Subscription subscription) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + public void setDeliveredToSubscription() { //To change body of implemented methods use File | Settings | File Templates. @@ -327,9 +334,9 @@ public class AbstractHeadersExchangeTestBase extends TestCase //To change body of implemented methods use File | Settings | File Templates. } - public String debugIdentity() + public boolean releaseButRetain() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean immediateAndNotDelivered() @@ -337,11 +344,26 @@ public class AbstractHeadersExchangeTestBase extends TestCase return false; //To change body of implemented methods use File | Settings | File Templates. } - public void setRedelivered(boolean b) + public void setRedelivered() { //To change body of implemented methods use File | Settings | File Templates. } + public AMQMessageHeader getMessageHeader() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isPersistent() + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isRedelivered() + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + public Subscription getDeliveredSubscription() { return null; //To change body of implemented methods use File | Settings | File Templates. @@ -362,17 +384,22 @@ public class AbstractHeadersExchangeTestBase extends TestCase return false; //To change body of implemented methods use File | Settings | File Templates. } - public void requeue(StoreContext storeContext) throws AMQException + public void requeue() + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void requeue(Subscription subscription) { //To change body of implemented methods use File | Settings | File Templates. } - public void dequeue(final StoreContext storeContext) throws FailedDequeueException + public void dequeue() { //To change body of implemented methods use File | Settings | File Templates. } - public void dispose(final StoreContext storeContext) throws MessageCleanupException + public void dispose() { //To change body of implemented methods use File | Settings | File Templates. } @@ -382,7 +409,12 @@ public class AbstractHeadersExchangeTestBase extends TestCase //To change body of implemented methods use File | Settings | File Templates. } - public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException + public void discard() + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void routeToAlternate() { //To change body of implemented methods use File | Settings | File Templates. } @@ -421,15 +453,16 @@ public class AbstractHeadersExchangeTestBase extends TestCase */ static class Message extends AMQMessage { + private static AtomicLong _messageId = new AtomicLong(); + private class TestIncomingMessage extends IncomingMessage { public TestIncomingMessage(final long messageId, final MessagePublishInfo info, - final TransactionalContext txnContext, final AMQProtocolSession publisher) { - super(messageId, info, txnContext, publisher); + super(info); } @@ -439,7 +472,7 @@ public class AbstractHeadersExchangeTestBase extends TestCase } - public ContentHeaderBody getContentHeaderBody() + public ContentHeaderBody getContentHeader() { try { @@ -454,15 +487,6 @@ public class AbstractHeadersExchangeTestBase extends TestCase private IncomingMessage _incoming; - private static MessageStore _messageStore = new SkeletonMessageStore(); - - private static StoreContext _storeContext = new StoreContext(); - - - private static TransactionalContext _txnContext = new NonTransactionalContext(_messageStore, _storeContext, - null, - new LinkedList<RequiredDeliveryException>() - ); Message(AMQProtocolSession protocolSession, String id, String... headers) throws AMQException { @@ -471,7 +495,7 @@ public class AbstractHeadersExchangeTestBase extends TestCase Message(AMQProtocolSession protocolSession, String id, FieldTable headers) throws AMQException { - this(protocolSession, _messageStore.getNewMessageId(),getPublishRequest(id), getContentHeader(headers), null); + this(protocolSession, _messageId.incrementAndGet(),getPublishRequest(id), getContentHeader(headers), Collections.EMPTY_LIST); } public IncomingMessage getIncomingMessage() @@ -484,46 +508,34 @@ public class AbstractHeadersExchangeTestBase extends TestCase ContentHeaderBody header, List<ContentBody> bodies) throws AMQException { - super(createMessageHandle(messageId, publish, header), _txnContext.getStoreContext(), publish); + super(new MockStoredMessage(messageId, publish, header)); + + StoredMessage<MessageMetaData> storedMessage = getStoredMessage(); + int pos = 0; + for(ContentBody body : bodies) + { + storedMessage.addContent(pos, body.payload.duplicate().buf()); + pos += body.payload.limit(); + } - - _incoming = new TestIncomingMessage(getMessageId(),publish, _txnContext, protocolsession); + _incoming = new TestIncomingMessage(getMessageId(),publish, protocolsession); _incoming.setContentHeaderBody(header); } - private static AMQMessageHandle createMessageHandle(final long messageId, - final MessagePublishInfo publish, - final ContentHeaderBody header) - { - - final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, - _messageStore, - true); - - try - { - amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),publish,header); - } - catch (AMQException e) - { - - } - return amqMessageHandle; - } private Message(AMQMessage msg) throws AMQException { - super(msg); + super(msg.getStoredMessage()); } void route(Exchange exchange) throws AMQException { - exchange.route(_incoming); + _incoming.enqueue(exchange.route(_incoming)); } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java index ac12e050b4..016f7eacbe 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java @@ -29,6 +29,7 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.management.ManagedObject; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java index 86ba96bf5d..dc47951548 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java @@ -22,16 +22,95 @@ package org.apache.qpid.server.exchange; import java.util.Map; import java.util.HashMap; +import java.util.Set; import junit.framework.TestCase; import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.message.AMQMessageHeader; /** */ public class HeadersBindingTest extends TestCase { + + private class MockHeader implements AMQMessageHeader + { + + private final Map<String, Object> _headers = new HashMap<String, Object>(); + + public String getCorrelationId() + { + return null; + } + + public long getExpiration() + { + return 0; + } + + public String getMessageId() + { + return null; + } + + public String getMimeType() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public String getEncoding() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public byte getPriority() + { + return 0; + } + + public long getTimestamp() + { + return 0; + } + + public String getType() + { + return null; + } + + public String getReplyTo() + { + return null; + } + + public Object getHeader(String name) + { + return _headers.get(name); + } + + public boolean containsHeaders(Set<String> names) + { + return _headers.keySet().containsAll(names); + } + + public boolean containsHeader(String name) + { + return _headers.containsKey(name); + } + + public void setString(String key, String value) + { + setObject(key,value); + } + + public void setObject(String key, Object value) + { + _headers.put(key,value); + } + } + private FieldTable bindHeaders = new FieldTable(); - private FieldTable matchHeaders = new FieldTable(); + private MockHeader matchHeaders = new MockHeader(); public void testDefault_1() { diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java index 750a1cd081..580bc78b8d 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -35,7 +35,8 @@ public class HeadersExchangeTest extends AbstractHeadersExchangeTestBase super.setUp(); // AR will use the NullAR by default // Just use the first vhost. - VirtualHost virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next(); + VirtualHost + virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next(); _protocolSession = new InternalTestProtocolSession(virtualHost); } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java index 82b8f76efc..9d7a323b6d 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/TopicExchangeTest.java @@ -14,9 +14,9 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.exchange; @@ -25,28 +25,24 @@ import junit.framework.Assert; import org.apache.qpid.server.queue.*; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.MemoryMessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.RequiredDeliveryException; import org.apache.qpid.server.protocol.InternalTestProtocolSession; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import java.util.LinkedList; - -public class DestWildExchangeTest extends TestCase +public class TopicExchangeTest extends TestCase { TopicExchange _exchange; VirtualHost _vhost; MessageStore _store; - StoreContext _context; InternalTestProtocolSession _protocolSession; @@ -56,27 +52,26 @@ public class DestWildExchangeTest extends TestCase _exchange = new TopicExchange(); _vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next(); _store = new MemoryMessageStore(); - _context = new StoreContext(); _protocolSession = new InternalTestProtocolSession(_vhost); } public void tearDown() { - ApplicationRegistry.remove(); + ApplicationRegistry.remove(); } public void testNoRoute() throws AMQException { - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null); + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null); _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null); MessagePublishInfo info = new PublishInfo(new AMQShortString("a.b")); - IncomingMessage message = new IncomingMessage(0L, info, null, _protocolSession); + IncomingMessage message = new IncomingMessage(info); - _exchange.route(message); + message.enqueue(_exchange.route(message)); Assert.assertEquals(0, queue.getMessageCount()); } @@ -89,33 +84,20 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.b"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.c"); - try - { - routeMessage(message); - fail("Message has no route and should fail to be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); } @@ -129,52 +111,33 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.b"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.c"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + int queueCount = routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a"); - try - { - routeMessage(message); - fail("Message has no route and should fail to be routed"); - } - catch (AMQException nre) - { - } + + queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); } @@ -187,89 +150,56 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.b.c"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + int queueCount = routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.b"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + queueCount = routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.c"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + queueCount = routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has route and should be routed"); - } + queueCount = routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("b"); - try - { - routeMessage(message); - fail("Message has no route and should fail to be routed"); - } - catch (AMQException nre) - { - } + + queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); } @@ -283,38 +213,24 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.c.d.b"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has no route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.c.b"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has no route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); } @@ -327,66 +243,39 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.c.b.b"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.a.b.c"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has no route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.b.c.b"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.b.c.b.c"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has no route and should be routed"); - - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); } @@ -400,34 +289,21 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.c.b.b.c"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.a.b.c.d"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has no route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); } @@ -440,33 +316,20 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.c.b.b.c"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); message = createMessage("a.a.b.c.d"); - try - { - routeMessage(message); - } - catch (AMQException nre) - { - fail("Message has no route and should be routed"); - } + routeMessage(message); Assert.assertEquals(1, queue.getMessageCount()); - Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId()); + Assert.assertEquals("Wrong message recevied", (Object) message.getMessageNumber(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageNumber()); - queue.deleteMessageFromTop(_context); + queue.deleteMessageFromTop(); Assert.assertEquals(0, queue.getMessageCount()); } @@ -479,25 +342,26 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.b.c"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); } - private void routeMessage(final IncomingMessage message) + private int routeMessage(final IncomingMessage message) throws AMQException { - _exchange.route(message); - message.routingComplete(_store, new MessageHandleFactory()); - message.deliverToQueues(); + MessageMetaData mmd = message.headersReceived(); + message.setStoredMessage(_store.addMessage(mmd)); + + message.enqueue(_exchange.route(message)); + AMQMessage msg = new AMQMessage(message.getStoredMessage()); + for(AMQQueue q : message.getDestinationQueues()) + { + q.enqueue(msg); + } + return message.getDestinationQueues().size(); } public void testMoreRouting() throws AMQException @@ -508,14 +372,8 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a.b.c"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); @@ -529,14 +387,8 @@ public class DestWildExchangeTest extends TestCase IncomingMessage message = createMessage("a"); - try - { - routeMessage(message); - fail("Message has route and should not be routed"); - } - catch (AMQException nre) - { - } + int queueCount = routeMessage(message); + Assert.assertEquals("Message should not route to any queues", 0, queueCount); Assert.assertEquals(0, queue.getMessageCount()); @@ -546,12 +398,11 @@ public class DestWildExchangeTest extends TestCase { MessagePublishInfo info = new PublishInfo(new AMQShortString(s)); - TransactionalContext trancontext = new NonTransactionalContext(_store, _context, null, - new LinkedList<RequiredDeliveryException>() - ); - - IncomingMessage message = new IncomingMessage(0L, info, trancontext,_protocolSession); - message.setContentHeaderBody( new ContentHeaderBody()); + IncomingMessage message = new IncomingMessage(info); + final ContentHeaderBody chb = new ContentHeaderBody(); + BasicContentHeaderProperties props = new BasicContentHeaderProperties(); + chb.properties = props; + message.setContentHeaderBody(chb); return message; @@ -574,7 +425,7 @@ public class DestWildExchangeTest extends TestCase public void setExchange(AMQShortString exchange) { - + } public boolean isImmediate() diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java index 0fa126dedb..46dc677921 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPChannelActorTest.java @@ -121,7 +121,7 @@ public class AMQPChannelActorTest extends TestCase // Verify that the message has the correct type assertTrue("Message contains the [con: prefix", logs.get(0).toString().contains("[con:")); - + // Verify that all the values were presented to the MessageFormatter // so we will not end up with '{n}' entries in the log. diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java index 1b25844a14..98c14efe4d 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AMQPConnectionActorTest.java @@ -75,7 +75,7 @@ public class AMQPConnectionActorTest extends TestCase // Correctly Close the AR we created ApplicationRegistry.remove(); - super.tearDown(); + super.tearDown(); } private void setUpWithConfig(ServerConfiguration serverConfig) throws AMQException diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java index e02993b840..e3280a4076 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/messages/MessageStoreMessagesTest.java @@ -41,12 +41,12 @@ public class MessageStoreMessagesTest extends AbstractTestMessages { String location = "/path/to/the/message/store.files"; - _logMessage = MessageStoreMessages.MST_1002(location); + _logMessage = ConfigStoreMessages.CFG_1002(location); List<Object> log = performLog(); String[] expected = {"Store location :", location}; - validateLogMessage(log, "MST-1002", expected); + validateLogMessage(log, "CFG-1002", expected); } public void testMessage1003() @@ -59,7 +59,7 @@ public class MessageStoreMessagesTest extends AbstractTestMessages validateLogMessage(log, "MST-1003", expected); } - public void testMessage1004() + /* public void testMessage1004() { _logMessage = MessageStoreMessages.MST_1004(null,false); List<Object> log = performLog(); @@ -91,7 +91,7 @@ public class MessageStoreMessagesTest extends AbstractTestMessages // Here we use MessageFormat to ensure the messasgeCount of 2000 is // reformated for display as '2,000' - String[] expected = {"Recovered ", + String[] expected = {"Recovered ", MessageFormat.format("{0,number}", messasgeCount), "messages for queue", queueName}; @@ -119,5 +119,5 @@ public class MessageStoreMessagesTest extends AbstractTestMessages validateLogMessage(log, "MST-1006", expected); } - + */ } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java index bc36c61382..e6561a06b9 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java @@ -23,19 +23,16 @@ package org.apache.qpid.server.protocol; import junit.framework.TestCase; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.SkeletonMessageStore; import javax.management.JMException; -import java.security.Principal; /** Test class to test MBean operations for AMQMinaProtocolSession. */ public class AMQProtocolSessionMBeanTest extends TestCase diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java index ec7bf1cb72..681e513ecb 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java @@ -21,19 +21,19 @@ package org.apache.qpid.server.protocol; import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; 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.output.ProtocolOutputConverter; -import org.apache.qpid.server.queue.AMQMessage; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.message.MessageContentSource; import org.apache.qpid.transport.TestNetworkDriver; public class InternalTestProtocolSession extends AMQProtocolEngine implements ProtocolOutputConverter @@ -70,6 +70,16 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr return (byte) 8; } + public void writeReturn(MessagePublishInfo messagePublishInfo, + ContentHeaderBody header, + MessageContentSource msgContent, + int channelId, + int replyCode, + AMQShortString replyText) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + public byte getProtocolMinorVersion() { return (byte) 0; @@ -82,12 +92,12 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr synchronized (_channelDelivers) { List<DeliveryPair> all =_channelDelivers.get(channelId).get(consumerTag); - + if (all == null) { return new ArrayList<DeliveryPair>(0); } - + List<DeliveryPair> msgs = all.subList(0, count); List<DeliveryPair> response = new ArrayList<DeliveryPair>(msgs); @@ -108,7 +118,7 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr { } - public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException + public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException { _deliveryCount.incrementAndGet(); @@ -130,11 +140,11 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr consumers.put(consumerTag, consumerDelivers); } - consumerDelivers.add(new DeliveryPair(deliveryTag, message)); + consumerDelivers.add(new DeliveryPair(deliveryTag, (AMQMessage)entry.getMessage())); } } - public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException + public void writeGetOk(QueueEntry message, int channelId, long deliveryTag, int queueSize) throws AMQException { } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java index e37492bcb0..13e712dbac 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java @@ -22,17 +22,10 @@ package org.apache.qpid.server.protocol; import junit.framework.TestCase; import org.apache.qpid.AMQException; -import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.AMQException; -import org.apache.qpid.protocol.AMQConstant; - -import java.security.Principal; /** Test class to test MBean operations for AMQMinaProtocolSession. */ public class MaxChannelsTest extends TestCase @@ -66,14 +59,14 @@ public class MaxChannelsTest extends TestCase } assertEquals("Maximum number of channels not set.", new Long(maxChannels), new Long(_session.getChannels().size())); } - + @Override public void setUp() { //Highlight that this test will cause a new AR to be created ApplicationRegistry.getInstance(); } - + @Override public void tearDown() throws Exception { @@ -87,7 +80,7 @@ public class MaxChannelsTest extends TestCase { // Correctly Close the AR we created ApplicationRegistry.remove(); - } + } } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java index aff7af6952..dd013e6ad5 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.queue; /* - * + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -8,21 +8,22 @@ package org.apache.qpid.server.queue; * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * + * */ import java.util.ArrayList; import org.apache.qpid.AMQException; +import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import junit.framework.AssertionFailedError; @@ -42,38 +43,38 @@ public class AMQPriorityQueueTest extends SimpleAMQQueueTest { // Enqueue messages in order - _queue.enqueue(null, createMessage(1L, (byte) 10)); - _queue.enqueue(null, createMessage(2L, (byte) 4)); - _queue.enqueue(null, createMessage(3L, (byte) 0)); - + _queue.enqueue(createMessage(1L, (byte) 10)); + _queue.enqueue(createMessage(2L, (byte) 4)); + _queue.enqueue(createMessage(3L, (byte) 0)); + // Enqueue messages in reverse order - _queue.enqueue(null, createMessage(4L, (byte) 0)); - _queue.enqueue(null, createMessage(5L, (byte) 4)); - _queue.enqueue(null, createMessage(6L, (byte) 10)); - + _queue.enqueue(createMessage(4L, (byte) 0)); + _queue.enqueue(createMessage(5L, (byte) 4)); + _queue.enqueue(createMessage(6L, (byte) 10)); + // Enqueue messages out of order - _queue.enqueue(null, createMessage(7L, (byte) 4)); - _queue.enqueue(null, createMessage(8L, (byte) 10)); - _queue.enqueue(null, createMessage(9L, (byte) 0)); - + _queue.enqueue(createMessage(7L, (byte) 4)); + _queue.enqueue(createMessage(8L, (byte) 10)); + _queue.enqueue(createMessage(9L, (byte) 0)); + // Register subscriber _queue.registerSubscription(_subscription, false); Thread.sleep(150); - + ArrayList<QueueEntry> msgs = _subscription.getMessages(); try { - assertEquals(new Long(1L), msgs.get(0).getMessage().getMessageId()); - assertEquals(new Long(6L), msgs.get(1).getMessage().getMessageId()); - assertEquals(new Long(8L), msgs.get(2).getMessage().getMessageId()); + assertEquals(new Long(1L), msgs.get(0).getMessage().getMessageNumber()); + assertEquals(new Long(6L), msgs.get(1).getMessage().getMessageNumber()); + assertEquals(new Long(8L), msgs.get(2).getMessage().getMessageNumber()); - assertEquals(new Long(2L), msgs.get(3).getMessage().getMessageId()); - assertEquals(new Long(5L), msgs.get(4).getMessage().getMessageId()); - assertEquals(new Long(7L), msgs.get(5).getMessage().getMessageId()); + assertEquals(new Long(2L), msgs.get(3).getMessage().getMessageNumber()); + assertEquals(new Long(5L), msgs.get(4).getMessage().getMessageNumber()); + assertEquals(new Long(7L), msgs.get(5).getMessage().getMessageNumber()); - assertEquals(new Long(3L), msgs.get(6).getMessage().getMessageId()); - assertEquals(new Long(4L), msgs.get(7).getMessage().getMessageId()); - assertEquals(new Long(9L), msgs.get(8).getMessage().getMessageId()); + assertEquals(new Long(3L), msgs.get(6).getMessage().getMessageNumber()); + assertEquals(new Long(4L), msgs.get(7).getMessage().getMessageNumber()); + assertEquals(new Long(9L), msgs.get(8).getMessage().getMessageNumber()); } catch (AssertionFailedError afe) { @@ -81,7 +82,7 @@ public class AMQPriorityQueueTest extends SimpleAMQQueueTest int index = 1; for (QueueEntry qe : msgs) { - System.err.println(index + ":" + qe.getMessage().getMessageId()); + System.err.println(index + ":" + qe.getMessage().getMessageNumber()); index++; } @@ -98,10 +99,10 @@ public class AMQPriorityQueueTest extends SimpleAMQQueueTest msg.getContentHeaderBody().properties = props; return msg; } - + protected AMQMessage createMessage(Long id) throws AMQException { return createMessage(id, (byte) 0); } - + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java index 19470e6226..5f0d77afea 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java @@ -20,21 +20,17 @@ */ package org.apache.qpid.server.queue; -import java.util.ArrayList; -import java.util.LinkedList; - -import javax.management.Notification; - import junit.framework.TestCase; - import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.protocol.AMQProtocolEngine; import org.apache.qpid.server.protocol.InternalTestProtocolSession; @@ -42,16 +38,16 @@ import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.store.MemoryMessageStore; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; import org.apache.qpid.server.virtualhost.VirtualHost; +import javax.management.Notification; +import java.util.ArrayList; + /** This class tests all the alerts an AMQQueue can throw based on threshold values of different parameters */ public class AMQQueueAlertTest extends TestCase -{ +{ private final static long MAX_MESSAGE_COUNT = 50; private final static long MAX_MESSAGE_AGE = 250; // 0.25 sec private final static long MAX_MESSAGE_SIZE = 2000; // 2 KB @@ -61,11 +57,6 @@ public class AMQQueueAlertTest extends TestCase private VirtualHost _virtualHost; private AMQProtocolEngine _protocolSession; private MessageStore _messageStore = new MemoryMessageStore(); - private StoreContext _storeContext = new StoreContext(); - private TransactionalContext _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext, - null, - new LinkedList<RequiredDeliveryException>() - ); private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE; /** @@ -75,6 +66,10 @@ public class AMQQueueAlertTest extends TestCase */ public void testMessageCountAlert() throws Exception { + _protocolSession = new InternalTestProtocolSession(_virtualHost); + AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore); + _protocolSession.addChannel(channel); + _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue1"), false, new AMQShortString("AMQueueAlertTest"), false, _virtualHost, null); @@ -82,7 +77,7 @@ public class AMQQueueAlertTest extends TestCase _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); - sendMessages(MAX_MESSAGE_COUNT, 256l); + sendMessages(channel, MAX_MESSAGE_COUNT, 256l); assertTrue(_queueMBean.getMessageCount() == MAX_MESSAGE_COUNT); Notification lastNotification = _queueMBean.getLastNotification(); @@ -99,6 +94,10 @@ public class AMQQueueAlertTest extends TestCase */ public void testMessageSizeAlert() throws Exception { + _protocolSession = new InternalTestProtocolSession(_virtualHost); + AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore); + _protocolSession.addChannel(channel); + _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue2"), false, new AMQShortString("AMQueueAlertTest"), false, _virtualHost, null); @@ -106,7 +105,7 @@ public class AMQQueueAlertTest extends TestCase _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); _queueMBean.setMaximumMessageSize(MAX_MESSAGE_SIZE); - sendMessages(1, MAX_MESSAGE_SIZE * 2); + sendMessages(channel, 1, MAX_MESSAGE_SIZE * 2); assertTrue(_queueMBean.getMessageCount() == 1); Notification lastNotification = _queueMBean.getLastNotification(); @@ -125,6 +124,10 @@ public class AMQQueueAlertTest extends TestCase */ public void testQueueDepthAlertNoSubscriber() throws Exception { + _protocolSession = new InternalTestProtocolSession(_virtualHost); + AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore); + _protocolSession.addChannel(channel); + _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue3"), false, new AMQShortString("AMQueueAlertTest"), false, _virtualHost, null); @@ -134,7 +137,7 @@ public class AMQQueueAlertTest extends TestCase while (_queue.getQueueDepth() < MAX_QUEUE_DEPTH) { - sendMessages(1, MAX_MESSAGE_SIZE); + sendMessages(channel, 1, MAX_MESSAGE_SIZE); } Notification lastNotification = _queueMBean.getLastNotification(); @@ -154,6 +157,10 @@ public class AMQQueueAlertTest extends TestCase */ public void testMessageAgeAlert() throws Exception { + _protocolSession = new InternalTestProtocolSession(_virtualHost); + AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore); + _protocolSession.addChannel(channel); + _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue4"), false, new AMQShortString("AMQueueAlertTest"), false, _virtualHost, null); @@ -161,7 +168,7 @@ public class AMQQueueAlertTest extends TestCase _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); _queueMBean.setMaximumMessageAge(MAX_MESSAGE_AGE); - sendMessages(1, MAX_MESSAGE_SIZE); + sendMessages(channel, 1, MAX_MESSAGE_SIZE); // Ensure message sits on queue long enough to age. Thread.sleep(MAX_MESSAGE_AGE * 2); @@ -201,7 +208,7 @@ public class AMQQueueAlertTest extends TestCase // Send messages(no of message to be little more than what can cause a Queue_Depth alert) int messageCount = Math.round(MAX_QUEUE_DEPTH / MAX_MESSAGE_SIZE) + 10; long totalSize = (messageCount * MAX_MESSAGE_SIZE); - sendMessages(messageCount, MAX_MESSAGE_SIZE); + sendMessages(channel, messageCount, MAX_MESSAGE_SIZE); // Check queueDepth. There should be no messages on the queue and as the subscriber is listening // so there should be no Queue_Deoth alert raised @@ -228,7 +235,7 @@ public class AMQQueueAlertTest extends TestCase _queue.registerSubscription( subscription2, false); - + while (_queue.getUndeliveredMessageCount()!= 0) { Thread.sleep(100); @@ -247,7 +254,7 @@ public class AMQQueueAlertTest extends TestCase _queueMBean.clearQueue(); assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth())); } - + protected IncomingMessage message(final boolean immediate, long size) throws AMQException { MessagePublishInfo publish = new MessagePublishInfo() @@ -280,8 +287,10 @@ public class AMQQueueAlertTest extends TestCase }; ContentHeaderBody contentHeaderBody = new ContentHeaderBody(); + BasicContentHeaderProperties props = new BasicContentHeaderProperties(); + contentHeaderBody.properties = props; contentHeaderBody.bodySize = size; // in bytes - IncomingMessage message = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession); + IncomingMessage message = new IncomingMessage(publish); message.setContentHeaderBody(contentHeaderBody); return message; @@ -305,16 +314,19 @@ public class AMQQueueAlertTest extends TestCase } - private void sendMessages(long messageCount, final long size) throws AMQException + private void sendMessages(AMQChannel channel, long messageCount, final long size) throws AMQException { IncomingMessage[] messages = new IncomingMessage[(int) messageCount]; + MessageMetaData[] metaData = new MessageMetaData[(int) messageCount]; for (int i = 0; i < messages.length; i++) { messages[i] = message(false, size); ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); qs.add(_queue); + metaData[i] = messages[i].headersReceived(); + messages[i].setStoredMessage(_messageStore.addMessage(metaData[i])); + messages[i].enqueue(qs); - messages[i].routingComplete(_messageStore, new MessageHandleFactory()); } @@ -324,6 +336,10 @@ public class AMQQueueAlertTest extends TestCase ByteBuffer _data = ByteBuffer.allocate((int)size); + { + _data.limit((int)size); + } + public int getSize() { return (int) size; @@ -336,10 +352,12 @@ public class AMQQueueAlertTest extends TestCase public void reduceToFit() { - + } }); - messages[i].deliverToQueues(); + + _queue.enqueue(new AMQMessage(messages[i].getStoredMessage())); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java index e692069663..97f061fdd1 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java @@ -25,7 +25,6 @@ import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; public class AMQQueueFactoryTest extends TestCase { @@ -55,31 +54,18 @@ public class AMQQueueFactoryTest extends TestCase FieldTable fieldTable = new FieldTable(); fieldTable.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), 5); - try - { - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testPriorityQueue"), false, new AMQShortString("owner"), false, - _virtualHost, fieldTable); - assertEquals("Queue not a priorty queue", AMQPriorityQueue.class, queue.getClass()); - } - catch (AMQException e) - { - fail(e.getMessage()); - } + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testPriorityQueue"), false, new AMQShortString("owner"), false, + _virtualHost, fieldTable); + + assertEquals("Queue not a priorty queue", AMQPriorityQueue.class, queue.getClass()); } public void testSimpleQueueRegistration() { - try - { - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("owner"), false, - _virtualHost, null); - assertEquals("Queue not a simple queue", SimpleAMQQueue.class, queue.getClass()); - } - catch (AMQException e) - { - fail(e.getMessage()); - } + AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("owner"), false, + _virtualHost, null); + assertEquals("Queue not a simple queue", SimpleAMQQueue.class, queue.getClass()); } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java index 03eb7021ad..3bb8d397be 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java @@ -29,7 +29,10 @@ import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.util.TestApplicationRegistry; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionFactory; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; @@ -38,19 +41,15 @@ import org.apache.qpid.server.protocol.InternalTestProtocolSession; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.txn.NonTransactionalContext; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.store.MemoryMessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.mina.common.ByteBuffer; +import org.apache.commons.configuration.PropertiesConfiguration; import javax.management.JMException; import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Collections; /** * Test class to test AMQQueueMBean attribtues and operations @@ -61,8 +60,6 @@ public class AMQQueueMBeanTest extends TestCase private AMQQueue _queue; private AMQQueueMBean _queueMBean; private MessageStore _messageStore; - private StoreContext _storeContext = new StoreContext(); - private TransactionalContext _transactionalContext; private VirtualHost _virtualHost; private AMQProtocolSession _protocolSession; private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE; @@ -108,7 +105,7 @@ public class AMQQueueMBeanTest extends TestCase //Ensure that the data has been removed from the Store verifyBrokerState(); } - + public void testDeleteMessages() throws Exception { int messageCount = 10; @@ -129,9 +126,9 @@ public class AMQQueueMBeanTest extends TestCase } catch(Exception e) { - + } - + //delete last message, leaving 2nd to 9th _queueMBean.deleteMessages(10L,10L); assertTrue(_queueMBean.getMessageCount() == (messageCount - 2)); @@ -143,7 +140,7 @@ public class AMQQueueMBeanTest extends TestCase } catch(Exception e) { - + } //delete remaining messages, leaving none @@ -159,18 +156,16 @@ public class AMQQueueMBeanTest extends TestCase private void verifyBrokerState() { - TestableMemoryMessageStore store = new TestableMemoryMessageStore((MemoryMessageStore) _virtualHost.getMessageStore()); + TestableMemoryMessageStore store = (TestableMemoryMessageStore)_virtualHost.getMessageStore(); // Unlike MessageReturnTest there is no need for a delay as there this thread does the clean up. - assertNotNull("ContentBodyMap should not be null", store.getContentBodyMap()); - assertEquals("Expected the store to have no content:" + store.getContentBodyMap(), 0, store.getContentBodyMap().size()); - assertNotNull("MessageMetaDataMap should not be null", store.getMessageMetaDataMap()); - assertEquals("Expected the store to have no metadata:" + store.getMessageMetaDataMap(), 0, store.getMessageMetaDataMap().size()); + + assertEquals("Store should have no messages:" + store.getMessageCount(), 0, store.getMessageCount()); } public void testConsumerCount() throws AMQException { - + assertTrue(_queue.getActiveConsumerCount() == 0); assertTrue(_queueMBean.getActiveConsumerCount() == 0); @@ -182,7 +177,7 @@ public class AMQQueueMBeanTest extends TestCase Subscription subscription = SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), protocolSession, new AMQShortString("test"), false, null, false, channel.getCreditManager()); - + _queue.registerSubscription(subscription, false); assertEquals(1,(int)_queueMBean.getActiveConsumerCount()); @@ -225,7 +220,6 @@ public class AMQQueueMBeanTest extends TestCase assertTrue(_queueMBean.getMaximumQueueDepth() == (maxQueueDepth)); assertTrue(_queueMBean.getName().equals("testQueue")); - assertTrue(_queueMBean.getOwner().equals("AMQueueMBeanTest")); assertFalse(_queueMBean.isAutoDelete()); assertFalse(_queueMBean.isDurable()); } @@ -261,7 +255,7 @@ public class AMQQueueMBeanTest extends TestCase { } - + try { long end = Integer.MAX_VALUE; @@ -275,17 +269,22 @@ public class AMQQueueMBeanTest extends TestCase } IncomingMessage msg = message(false, false); - long id = msg.getMessageId(); - _queue.clearQueue(_storeContext); + _queue.clearQueue(); ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); qs.add(_queue); msg.enqueue(qs); - msg.routingComplete(_messageStore, new MessageHandleFactory()); + MessageMetaData mmd = msg.headersReceived(); + msg.setStoredMessage(_messageStore.addMessage(mmd)); + long id = msg.getMessageNumber(); msg.addContentBodyFrame(new ContentChunk() { ByteBuffer _data = ByteBuffer.allocate((int)MESSAGE_SIZE); + { + _data.limit((int)MESSAGE_SIZE); + } + public int getSize() { return (int) MESSAGE_SIZE; @@ -301,7 +300,12 @@ public class AMQQueueMBeanTest extends TestCase } }); - msg.deliverToQueues(); + + AMQMessage m = new AMQMessage(msg.getStoredMessage()); + for(AMQQueue q : msg.getDestinationQueues()) + { + q.enqueue(m); + } // _queue.process(_storeContext, new QueueEntry(_queue, msg), false); _queueMBean.viewMessageContent(id); try @@ -350,7 +354,7 @@ public class AMQQueueMBeanTest extends TestCase contentHeaderBody.bodySize = MESSAGE_SIZE; // in bytes contentHeaderBody.properties = new BasicContentHeaderProperties(); ((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) (persistent ? 2 : 1)); - IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession); + IncomingMessage msg = new IncomingMessage(publish); msg.setContentHeaderBody(contentHeaderBody); return msg; @@ -360,15 +364,17 @@ public class AMQQueueMBeanTest extends TestCase protected void setUp() throws Exception { super.setUp(); - IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(); + + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.setProperty("virtualhosts.virtualhost.test.store.class", TestableMemoryMessageStore.class.getName()); + IApplicationRegistry applicationRegistry = new TestApplicationRegistry(new ServerConfiguration(configuration)); + ApplicationRegistry.initialise(applicationRegistry ); + + configuration.setProperty("virtualhosts.virtualhost.test.store.class", TestableMemoryMessageStore.class.getName()); + _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test"); _messageStore = _virtualHost.getMessageStore(); - _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext, - null, - new LinkedList<RequiredDeliveryException>() - ); - _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("AMQueueMBeanTest"), false, _virtualHost, null); _queueMBean = new AMQQueueMBean(_queue); @@ -391,7 +397,8 @@ public class AMQQueueMBeanTest extends TestCase currentMessage.enqueue(qs); // route header - currentMessage.routingComplete(_messageStore, new MessageHandleFactory()); + MessageMetaData mmd = currentMessage.headersReceived(); + currentMessage.setStoredMessage(_messageStore.addMessage(mmd)); // Add the body so we have somthing to test later currentMessage.addContentBodyFrame( @@ -400,7 +407,12 @@ public class AMQQueueMBeanTest extends TestCase .convertToContentChunk( new ContentBody(ByteBuffer.allocate((int) MESSAGE_SIZE), MESSAGE_SIZE))); - currentMessage.deliverToQueues(); + + AMQMessage m = new AMQMessage(currentMessage.getStoredMessage()); + for(AMQQueue q : currentMessage.getDestinationQueues()) + { + q.enqueue(m); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java index 79f7d75aa9..d64e533f72 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java @@ -28,7 +28,10 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.RequiredDeliveryException; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.protocol.InternalTestProtocolSession; import org.apache.qpid.server.protocol.AMQProtocolSession; @@ -39,15 +42,9 @@ import org.apache.qpid.server.flow.Pre0_10CreditManager; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.store.TestMemoryMessageStore; -import org.apache.qpid.server.store.StoreContext; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.txn.TransactionalContext; -import org.apache.qpid.server.util.NullApplicationRegistry; import java.util.ArrayList; -import java.util.LinkedList; import java.util.Set; -import java.util.Collections; /** * Tests that acknowledgements are handled correctly. @@ -62,8 +59,6 @@ public class AckTest extends TestCase private TestMemoryMessageStore _messageStore; - private StoreContext _storeContext = new StoreContext(); - private AMQChannel _channel; private AMQQueue _queue; @@ -99,11 +94,7 @@ public class AckTest extends TestCase private void publishMessages(int count, boolean persistent) throws AMQException { - TransactionalContext txnContext = new NonTransactionalContext(_messageStore, _storeContext, null, - new LinkedList<RequiredDeliveryException>() - ); _queue.registerSubscription(_subscription,false); - MessageHandleFactory factory = new MessageHandleFactory(); for (int i = 1; i <= count; i++) { // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) @@ -136,31 +127,50 @@ public class AckTest extends TestCase return new AMQShortString("rk"); } }; - IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publishBody, txnContext,_protocolSession); + final IncomingMessage msg = new IncomingMessage(publishBody); //IncomingMessage msg2 = null; + BasicContentHeaderProperties b = new BasicContentHeaderProperties(); + ContentHeaderBody cb = new ContentHeaderBody(); + cb.properties = b; + if (persistent) { - BasicContentHeaderProperties b = new BasicContentHeaderProperties(); //This is DeliveryMode.PERSISTENT b.setDeliveryMode((byte) 2); - ContentHeaderBody cb = new ContentHeaderBody(); - cb.properties = b; - msg.setContentHeaderBody(cb); - } - else - { - msg.setContentHeaderBody(new ContentHeaderBody()); } + + msg.setContentHeaderBody(cb); + // we increment the reference here since we are not delivering the messaging to any queues, which is where // the reference is normally incremented. The test is easier to construct if we have direct access to the // subscription ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); qs.add(_queue); msg.enqueue(qs); - msg.routingComplete(_messageStore, factory); + MessageMetaData mmd = msg.headersReceived(); + msg.setStoredMessage(_messageStore.addMessage(mmd)); if(msg.allContentReceived()) { - msg.deliverToQueues(); + ServerTransaction txn = new AutoCommitTransaction(_messageStore); + txn.enqueue(_queue, msg, new ServerTransaction.Action() { + public void postCommit() + { + try + { + _queue.enqueue(new AMQMessage(msg.getStoredMessage())); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + + public void onRollback() + { + //To change body of implemented methods use File | Settings | File Templates. + } + }); + } // we manually send the message to the subscription //_subscription.send(new QueueEntry(_queue,msg), _queue); @@ -178,8 +188,7 @@ public class AckTest extends TestCase publishMessages(msgCount, true); UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap(); - assertTrue(map.size() == msgCount); - assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount); + assertEquals("",msgCount,map.size()); Set<Long> deliveryTagSet = map.getDeliveryTags(); int i = 1; @@ -191,8 +200,6 @@ public class AckTest extends TestCase assertTrue(unackedMsg.getQueue() == _queue); } - assertTrue(map.size() == msgCount); - assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount); } /** @@ -207,8 +214,8 @@ public class AckTest extends TestCase UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap(); assertTrue(map.size() == 0); - assertTrue(_messageStore.getMessageMetaDataMap().size() == 0); - assertTrue(_messageStore.getContentBodyMap().size() == 0); + assertTrue(_messageStore.getMessageCount() == 0); + } @@ -224,8 +231,8 @@ public class AckTest extends TestCase UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap(); assertTrue(map.size() == 0); - assertTrue(_messageStore.getMessageMetaDataMap().size() == 0); - assertTrue(_messageStore.getContentBodyMap().size() == 0); + assertTrue(_messageStore.getMessageCount() == 0); + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java index 355ba6a362..7000df157e 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java @@ -20,25 +20,18 @@ */ package org.apache.qpid.server.queue; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.server.message.AMQMessage; public class MockAMQMessage extends AMQMessage { public MockAMQMessage(long messageId) throws AMQException { - super(new MockAMQMessageHandle(messageId) , - (StoreContext)null, - (MessagePublishInfo)new MockMessagePublishInfo()); + super(new MockStoredMessage(messageId)); } - protected MockAMQMessage(AMQMessage msg) - throws AMQException - { - super(msg); - } + @Override @@ -46,4 +39,5 @@ public class MockAMQMessage extends AMQMessage { return 0l; } + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java index a131c2a465..7c1f728664 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java @@ -23,23 +23,19 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.configuration.QueueConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.security.PrincipalHolder; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.AMQException; -import org.apache.commons.configuration.Configuration; import java.util.List; import java.util.Set; import java.util.Map; -import java.util.HashMap; -import java.util.LinkedList; public class MockAMQQueue implements AMQQueue { @@ -47,6 +43,10 @@ public class MockAMQQueue implements AMQQueue private AMQShortString _name; private VirtualHost _virtualhost; + private PrincipalHolder _principalHolder; + + private Object _exclusiveOwner; + public MockAMQQueue(String name) { _name = new AMQShortString(name); @@ -57,6 +57,11 @@ public class MockAMQQueue implements AMQQueue return _name; } + public void setNoLocal(boolean b) + { + + } + public boolean isDurable() { return false; //To change body of implemented methods use File | Settings | File Templates. @@ -162,17 +167,22 @@ public class MockAMQQueue implements AMQQueue return 0; //To change body of implemented methods use File | Settings | File Templates. } - public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException + public QueueEntry enqueue(ServerMessage message) throws AMQException { return null; //To change body of implemented methods use File | Settings | File Templates. } - public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException + public void requeue(QueueEntry entry) { //To change body of implemented methods use File | Settings | File Templates. } - public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException + public void requeue(QueueEntryImpl storeContext, Subscription subscription) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void dequeue(QueueEntry entry) { //To change body of implemented methods use File | Settings | File Templates. } @@ -211,23 +221,23 @@ public class MockAMQQueue implements AMQQueue { return null; //To change body of implemented methods use File | Settings | File Templates. } - + public List<QueueEntry> getMessagesRangeOnTheQueue(long fromPosition, long toPosition) { return null; } - public void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext) + public void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction storeContext) { //To change body of implemented methods use File | Settings | File Templates. } - public void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext) + public void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction storeContext) { //To change body of implemented methods use File | Settings | File Templates. } - public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext) + public void removeMessagesFromQueue(long fromMessageId, long toMessageId) { //To change body of implemented methods use File | Settings | File Templates. } @@ -286,16 +296,16 @@ public class MockAMQQueue implements AMQQueue return 0; //To change body of implemented methods use File | Settings | File Templates. } - public void deleteMessageFromTop(StoreContext storeContext) throws AMQException + public void deleteMessageFromTop() { //To change body of implemented methods use File | Settings | File Templates. } - public long clearQueue(StoreContext storeContext) throws AMQException + public long clearQueue() { return 0; //To change body of implemented methods use File | Settings | File Templates. } - + public void checkMessageStatus() throws AMQException { @@ -327,8 +337,28 @@ public class MockAMQQueue implements AMQQueue //To change body of implemented methods use File | Settings | File Templates. } + public boolean isExclusive() + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Exchange getAlternateExchange() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void setAlternateExchange(Exchange exchange) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public Map<String, Object> getArguments() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public void checkCapacity(AMQChannel channel) - { + { } public ManagedObject getManagedObject() @@ -343,7 +373,7 @@ public class MockAMQQueue implements AMQQueue public void setMinimumAlertRepeatGap(long value) { - + } public long getCapacity() @@ -368,7 +398,32 @@ public class MockAMQQueue implements AMQQueue public void configure(QueueConfiguration config) { - + + } + + public PrincipalHolder getPrincipalHolder() + { + return _principalHolder; } + public void setPrincipalHolder(PrincipalHolder principalHolder) + { + _principalHolder = principalHolder; + } + + public Object getExclusiveOwner() + { + return _exclusiveOwner; + } + + public void setExclusiveOwner(Object exclusiveOwner) + { + _exclusiveOwner = exclusiveOwner; + } + + + public String getResourceName() + { + return _name.toString(); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java index 37f91e7464..3f74cb973b 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java @@ -21,8 +21,9 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.subscription.Subscription; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.AMQMessage; public class MockQueueEntry implements QueueEntry { @@ -44,14 +45,14 @@ public class MockQueueEntry implements QueueEntry return false; } - public void addStateChangeListener(StateChangeListener listener) + public boolean isAcquiredBy(Subscription subscription) { - + return false; } - public String debugIdentity() + public void addStateChangeListener(StateChangeListener listener) { - return null; + } public boolean delete() @@ -59,17 +60,22 @@ public class MockQueueEntry implements QueueEntry return false; } - public void dequeue(StoreContext storeContext) throws FailedDequeueException + public void dequeue() + { + + } + + public void discard() { } - public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException + public void routeToAlternate() { } - public void dispose(StoreContext storeContext) throws MessageCleanupException + public void dispose() { } @@ -119,70 +125,95 @@ public class MockQueueEntry implements QueueEntry return false; } - + public boolean isQueueDeleted() { return false; } - + public boolean isRejectedBy(Subscription subscription) { return false; } - + public void reject() { } - + public void reject(Subscription subscription) { } - + public void release() { } - + public boolean releaseButRetain() + { + return false; + } + + public boolean removeStateChangeListener(StateChangeListener listener) { return false; } - - public void requeue(StoreContext storeContext) throws AMQException + + public void requeue() { } - + public void requeue(Subscription subscription) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setDeliveredToSubscription() { } - - public void setRedelivered(boolean b) + + public void setRedelivered() + { + + + } + + public AMQMessageHeader getMessageHeader() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public boolean isPersistent() + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + public boolean isRedelivered() + { + return false; } - + public int compareTo(QueueEntry o) { diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java new file mode 100755 index 0000000000..7dc491de4d --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java @@ -0,0 +1,92 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.StoredMessage; +import org.apache.qpid.server.message.MessageMetaData; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; + +import java.nio.ByteBuffer; + +public class MockStoredMessage implements StoredMessage<MessageMetaData> +{ + private long _messageId; + private MessageMetaData _metaData; + private final ByteBuffer _content; + + + public MockStoredMessage(long messageId) + { + this(messageId, new MockMessagePublishInfo(), new ContentHeaderBody(new BasicContentHeaderProperties(), 60)); + } + + public MockStoredMessage(long messageId, MessagePublishInfo info, ContentHeaderBody chb) + { + _messageId = messageId; + _metaData = new MessageMetaData(info, chb, 0); + _content = ByteBuffer.allocate(_metaData.getContentSize()); + + } + + public MessageMetaData getMetaData() + { + return _metaData; + } + + public long getMessageNumber() + { + return _messageId; + } + + public void addContent(int offsetInMessage, ByteBuffer src) + { + src = src.duplicate(); + ByteBuffer dst = _content.duplicate(); + dst.position(offsetInMessage); + dst.put(src); + } + + public int getContent(int offset, ByteBuffer dst) + { + ByteBuffer src = _content.duplicate(); + src.position(offset); + src = src.slice(); + if(dst.remaining() < src.limit()) + { + src.limit(dst.remaining()); + } + dst.put(src); + return src.limit(); + } + + public TransactionLog.StoreFuture flushToStore() + { + return MessageStore.IMMEDIATE_FUTURE; + } + + public void remove() + { + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java index 111e94f9bf..8c6574095b 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java @@ -1,6 +1,6 @@ package org.apache.qpid.server.queue; /* - * + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -8,16 +8,16 @@ package org.apache.qpid.server.queue; * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * + * */ @@ -31,21 +31,21 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.ContentHeaderProperties; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.DirectExchange; -import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.store.TestableMemoryMessageStore; +import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.subscription.MockSubscription; import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionImpl; -import org.apache.qpid.server.txn.NonTransactionalContext; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; public class SimpleAMQQueueTest extends TestCase { @@ -59,7 +59,7 @@ public class SimpleAMQQueueTest extends TestCase protected DirectExchange _exchange = new DirectExchange(); protected MockSubscription _subscription = new MockSubscription(); protected FieldTable _arguments = null; - + MessagePublishInfo info = new MessagePublishInfo() { @@ -88,7 +88,7 @@ public class SimpleAMQQueueTest extends TestCase return null; } }; - + @Override protected void setUp() throws Exception { @@ -97,7 +97,7 @@ public class SimpleAMQQueueTest extends TestCase ApplicationRegistry applicationRegistry = (ApplicationRegistry)ApplicationRegistry.getInstance(); PropertiesConfiguration env = new PropertiesConfiguration(); - _virtualHost = new VirtualHost(new VirtualHostConfiguration(getClass().getName(), env), _store); + _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration(getClass().getName(), env), _store); applicationRegistry.getVirtualHostRegistry().registerVirtualHost(_virtualHost); _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false, _virtualHost, _arguments); @@ -119,51 +119,51 @@ public class SimpleAMQQueueTest extends TestCase } catch (IllegalArgumentException e) { - assertTrue("Exception was not about missing name", + assertTrue("Exception was not about missing name", e.getMessage().contains("name")); } - + try { _queue = new SimpleAMQQueue(_qname, false, _owner, false, null); assertNull("Queue was created", _queue); } catch (IllegalArgumentException e) { - assertTrue("Exception was not about missing vhost", + assertTrue("Exception was not about missing vhost", e.getMessage().contains("Host")); } - _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false, + _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false, _virtualHost, _arguments); assertNotNull("Queue was not created", _queue); } - + public void testGetVirtualHost() { assertEquals("Virtual host was wrong", _virtualHost, _queue.getVirtualHost()); } - + public void testBinding() { try { _queue.bind(_exchange, _routingKey, null); - assertTrue("Routing key was not bound", + assertTrue("Routing key was not bound", _exchange.getBindings().containsKey(_routingKey)); - assertEquals("Queue was not bound to key", + assertEquals("Queue was not bound to key", _exchange.getBindings().get(_routingKey).get(0), _queue); - assertEquals("Exchange binding count", 1, + assertEquals("Exchange binding count", 1, _queue.getExchangeBindings().size()); - assertEquals("Wrong exchange bound", _routingKey, + assertEquals("Wrong exchange bound", _routingKey, _queue.getExchangeBindings().get(0).getRoutingKey()); - assertEquals("Wrong exchange bound", _exchange, + assertEquals("Wrong exchange bound", _exchange, _queue.getExchangeBindings().get(0).getExchange()); - + _queue.unBind(_exchange, _routingKey, null); - assertFalse("Routing key was still bound", + assertFalse("Routing key was still bound", _exchange.getBindings().containsKey(_routingKey)); - assertNull("Routing key was not empty", + assertNull("Routing key was not empty", _exchange.getBindings().get(_routingKey)); } catch (AMQException e) @@ -171,61 +171,61 @@ public class SimpleAMQQueueTest extends TestCase assertNull("Unexpected exception", e); } } - + public void testSubscription() throws AMQException { // Check adding a subscription adds it to the queue _queue.registerSubscription(_subscription, false); - assertEquals("Subscription did not get queue", _queue, + assertEquals("Subscription did not get queue", _queue, _subscription.getQueue()); - assertEquals("Queue does not have consumer", 1, + assertEquals("Queue does not have consumer", 1, _queue.getConsumerCount()); - assertEquals("Queue does not have active consumer", 1, + assertEquals("Queue does not have active consumer", 1, _queue.getActiveConsumerCount()); - + // Check sending a message ends up with the subscriber AMQMessage messageA = createMessage(new Long(24)); - _queue.enqueue(null, messageA); - assertEquals(messageA, _subscription.getLastSeenEntry().getMessage()); - + _queue.enqueue(messageA); + assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage()); + // Check removing the subscription removes it's information from the queue _queue.unregisterSubscription(_subscription); assertTrue("Subscription still had queue", _subscription.isClosed()); assertFalse("Queue still has consumer", 1 == _queue.getConsumerCount()); - assertFalse("Queue still has active consumer", + assertFalse("Queue still has active consumer", 1 == _queue.getActiveConsumerCount()); - + AMQMessage messageB = createMessage(new Long (25)); - _queue.enqueue(null, messageB); - QueueEntry entry = _subscription.getLastSeenEntry(); - assertNull(entry); + _queue.enqueue(messageB); + assertNull(_subscription.getQueueContext()); + } - + public void testQueueNoSubscriber() throws AMQException, InterruptedException { AMQMessage messageA = createMessage(new Long(24)); - _queue.enqueue(null, messageA); + _queue.enqueue(messageA); _queue.registerSubscription(_subscription, false); Thread.sleep(150); - assertEquals(messageA, _subscription.getLastSeenEntry().getMessage()); + assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage()); } public void testExclusiveConsumer() throws AMQException { // Check adding an exclusive subscription adds it to the queue _queue.registerSubscription(_subscription, true); - assertEquals("Subscription did not get queue", _queue, + assertEquals("Subscription did not get queue", _queue, _subscription.getQueue()); - assertEquals("Queue does not have consumer", 1, + assertEquals("Queue does not have consumer", 1, _queue.getConsumerCount()); - assertEquals("Queue does not have active consumer", 1, + assertEquals("Queue does not have active consumer", 1, _queue.getActiveConsumerCount()); // Check sending a message ends up with the subscriber AMQMessage messageA = createMessage(new Long(24)); - _queue.enqueue(null, messageA); - assertEquals(messageA, _subscription.getLastSeenEntry().getMessage()); - + _queue.enqueue(messageA); + assertEquals(messageA, _subscription.getQueueContext().getLastSeenEntry().getMessage()); + // Check we cannot add a second subscriber to the queue Subscription subB = new MockSubscription(); Exception ex = null; @@ -235,12 +235,12 @@ public class SimpleAMQQueueTest extends TestCase } catch (AMQException e) { - ex = e; + ex = e; } assertNotNull(ex); assertTrue(ex instanceof AMQException); - // Check we cannot add an exclusive subscriber to a queue with an + // Check we cannot add an exclusive subscriber to a queue with an // existing subscription _queue.unregisterSubscription(_subscription); _queue.registerSubscription(_subscription, false); @@ -250,35 +250,35 @@ public class SimpleAMQQueueTest extends TestCase } catch (AMQException e) { - ex = e; + ex = e; } assertNotNull(ex); } - - public void testAutoDeleteQueue() throws Exception + + public void testAutoDeleteQueue() throws Exception { _queue.stop(); - _queue = new SimpleAMQQueue(_qname, false, _owner, true, _virtualHost); + _queue = new SimpleAMQQueue(_qname, false, null, true, _virtualHost); _queue.registerSubscription(_subscription, false); AMQMessage message = createMessage(new Long(25)); - _queue.enqueue(null, message); + _queue.enqueue(message); _queue.unregisterSubscription(_subscription); assertTrue("Queue was not deleted when subscription was removed", _queue.isDeleted()); } - + public void testResend() throws Exception { _queue.registerSubscription(_subscription, false); Long id = new Long(26); AMQMessage message = createMessage(id); - _queue.enqueue(null, message); - QueueEntry entry = _subscription.getLastSeenEntry(); - entry.setRedelivered(true); + _queue.enqueue(message); + QueueEntry entry = _subscription.getQueueContext().getLastSeenEntry(); + entry.setRedelivered(); _queue.resend(entry, _subscription); - + } - + public void testGetFirstMessageId() throws Exception { // Create message @@ -286,7 +286,7 @@ public class SimpleAMQQueueTest extends TestCase AMQMessage message = createMessage(messageId); // Put message on queue - _queue.enqueue(null, message); + _queue.enqueue(message); // Get message id Long testmsgid = _queue.getMessagesOnTheQueue(1).get(0); @@ -302,7 +302,7 @@ public class SimpleAMQQueueTest extends TestCase Long messageId = new Long(i); AMQMessage message = createMessage(messageId); // Put message on queue - _queue.enqueue(null, message); + _queue.enqueue(message); } // Get message ids List<Long> msgids = _queue.getMessagesOnTheQueue(5); @@ -323,7 +323,7 @@ public class SimpleAMQQueueTest extends TestCase Long messageId = new Long(i); AMQMessage message = createMessage(messageId); // Put message on queue - _queue.enqueue(null, message); + _queue.enqueue(message); } // Get message ids List<Long> msgids = _queue.getMessagesOnTheQueue(5, 5); @@ -335,7 +335,7 @@ public class SimpleAMQQueueTest extends TestCase assertEquals("Message ID was wrong", messageId, msgids.get(i)); } } - + public void testGetMessagesRangeOnTheQueue() throws Exception { for (int i = 1 ; i <= 10; i++) @@ -344,142 +344,138 @@ public class SimpleAMQQueueTest extends TestCase Long messageId = new Long(i); AMQMessage message = createMessage(messageId); // Put message on queue - _queue.enqueue(null, message); + _queue.enqueue(message); } - + // Get non-existent 0th QueueEntry & check returned list was empty // (the position parameters in this method are indexed from 1) List<QueueEntry> entries = _queue.getMessagesRangeOnTheQueue(0, 0); assertTrue(entries.size() == 0); - + // Check that when 'from' is 0 it is ignored and the range continues from 1 entries = _queue.getMessagesRangeOnTheQueue(0, 2); assertTrue(entries.size() == 2); - long msgID = entries.get(0).getMessage().getMessageId(); + long msgID = entries.get(0).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 1L); - msgID = entries.get(1).getMessage().getMessageId(); + msgID = entries.get(1).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 2L); // Check that when 'from' is greater than 'to' the returned list is empty entries = _queue.getMessagesRangeOnTheQueue(5, 4); assertTrue(entries.size() == 0); - - // Get first QueueEntry & check id + + // Get first QueueEntry & check id entries = _queue.getMessagesRangeOnTheQueue(1, 1); assertTrue(entries.size() == 1); - msgID = entries.get(0).getMessage().getMessageId(); + msgID = entries.get(0).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 1L); - + // Get 5th,6th,7th entries and check id's entries = _queue.getMessagesRangeOnTheQueue(5, 7); assertTrue(entries.size() == 3); - msgID = entries.get(0).getMessage().getMessageId(); + msgID = entries.get(0).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 5L); - msgID = entries.get(1).getMessage().getMessageId(); + msgID = entries.get(1).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 6L); - msgID = entries.get(2).getMessage().getMessageId(); + msgID = entries.get(2).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 7L); - + // Get 10th QueueEntry & check id entries = _queue.getMessagesRangeOnTheQueue(10, 10); assertTrue(entries.size() == 1); - msgID = entries.get(0).getMessage().getMessageId(); + msgID = entries.get(0).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 10L); - + // Get non-existent 11th QueueEntry & check returned set was empty entries = _queue.getMessagesRangeOnTheQueue(11, 11); assertTrue(entries.size() == 0); - + // Get 9th,10th, and non-existent 11th entries & check result is of size 2 with correct IDs entries = _queue.getMessagesRangeOnTheQueue(9, 11); assertTrue(entries.size() == 2); - msgID = entries.get(0).getMessage().getMessageId(); + msgID = entries.get(0).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 9L); - msgID = entries.get(1).getMessage().getMessageId(); + msgID = entries.get(1).getMessage().getMessageNumber(); assertEquals("Message ID was wrong", msgID, 10L); } - + public void testEnqueueDequeueOfPersistentMessageToNonDurableQueue() throws AMQException { // Create IncomingMessage and nondurable queue - NonTransactionalContext txnContext = new NonTransactionalContext(_store, null, null, null); - IncomingMessage msg = new IncomingMessage(1L, info, txnContext, null); + final IncomingMessage msg = new IncomingMessage(info); ContentHeaderBody contentHeaderBody = new ContentHeaderBody(); contentHeaderBody.properties = new BasicContentHeaderProperties(); ((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) 2); msg.setContentHeaderBody(contentHeaderBody); - ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); - + + final ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); + // Send persistent message + qs.add(_queue); - msg.enqueue(qs); - msg.routingComplete(_store, new MessageHandleFactory()); - _store.storeMessageMetaData(null, new Long(1L), new MessageMetaData(info, contentHeaderBody, 1)); - + MessageMetaData metaData = msg.headersReceived(); + StoredMessage handle = _store.addMessage(metaData); + msg.setStoredMessage(handle); + + + ServerTransaction txn = new AutoCommitTransaction(_store); + + txn.enqueue(qs, msg, new ServerTransaction.Action() + { + public void postCommit() + { + msg.enqueue(qs); + } + + public void onRollback() + { + } + }); + + + // Check that it is enqueued AMQQueue data = _store.getMessages().get(1L); - assertNotNull(data); - + assertNull(data); + // Dequeue message MockQueueEntry entry = new MockQueueEntry(); - AMQMessage amqmsg = new AMQMessage(1L, _store, new MessageHandleFactory(), txnContext); - + AMQMessage amqmsg = new AMQMessage(handle); + entry.setMessage(amqmsg); - _queue.dequeue(null, entry); - + _queue.dequeue(entry); + // Check that it is dequeued data = _store.getMessages().get(1L); assertNull(data); } - // FIXME: move this to somewhere useful - private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody) - { - final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, - null, - false); - try - { - amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(), - publishBody, - new ContentHeaderBody() - { - public int getSize() - { - return 1; - } - }); - } - catch (AMQException e) - { - // won't happen - } - - - return amqMessageHandle; - } - public class TestMessage extends AMQMessage { private final long _tag; private int _count; - TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext) + TestMessage(long tag, long messageId, MessagePublishInfo publishBody) throws AMQException { - super(createMessageHandle(messageId, publishBody), storeContext, publishBody); + this(tag, messageId, publishBody, new ContentHeaderBody(1, 1, new BasicContentHeaderProperties(), 0)); + + } + TestMessage(long tag, long messageId, MessagePublishInfo publishBody, ContentHeaderBody chb) + throws AMQException + { + super(new MockStoredMessage(messageId, publishBody, chb)); _tag = tag; } - public boolean incrementReference() { _count++; return true; } - public void decrementReference(StoreContext context) + public void decrementReference() { _count--; } @@ -489,10 +485,10 @@ public class SimpleAMQQueueTest extends TestCase assertEquals("Wrong count for message with tag " + _tag, expected, _count); } } - + protected AMQMessage createMessage(Long id) throws AMQException { - AMQMessage messageA = new TestMessage(id, id, info, new StoreContext()); + AMQMessage messageA = new TestMessage(id, id, info); return messageA; } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java index 02de09c91f..ba94af5936 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java @@ -27,8 +27,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.AMQException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class SimpleAMQQueueThreadPoolTest extends TestCase { @@ -47,7 +45,7 @@ public class SimpleAMQQueueThreadPoolTest extends TestCase assertFalse("Creation did not start Pool.", ReferenceCountingExecutorService.getInstance().getPool().isShutdown()); assertEquals("References not increased", initialCount + 1, ReferenceCountingExecutorService.getInstance().getReferenceCount()); - + queue.stop(); assertEquals("References not decreased", initialCount , ReferenceCountingExecutorService.getInstance().getReferenceCount()); @@ -55,6 +53,6 @@ public class SimpleAMQQueueThreadPoolTest extends TestCase finally { ApplicationRegistry.remove(); - } + } } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java index 8102360ce0..44f9861e8d 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java @@ -57,11 +57,11 @@ public class ACLManagerTest extends TestCase BufferedWriter out = new BufferedWriter(new FileWriter(tmpFile)); out.write("<security><queueDenier>notyet</queueDenier><exchangeDenier>yes</exchangeDenier></security>"); out.close(); - + _conf = new SecurityConfiguration(new XMLConfiguration(tmpFile)); - + // Create ACLManager - + _pluginManager = new MockPluginManager(""); _authzManager = new ACLManager(_conf, _pluginManager); @@ -79,15 +79,15 @@ public class ACLManagerTest extends TestCase // Correctly Close the AR we created ApplicationRegistry.remove(); super.tearDown(); - } - + } + public void testACLManagerConfigurationPluginManager() throws Exception { AMQQueue queue = new MockAMQQueue("notyet"); AMQQueue otherQueue = new MockAMQQueue("other"); - + assertFalse(_authzManager.authoriseDelete(_session, queue)); - + // This should only be denied if the config hasn't been correctly passed in assertTrue(_authzManager.authoriseDelete(_session, otherQueue)); assertTrue(_authzManager.authorisePurge(_session, queue)); @@ -96,11 +96,11 @@ public class ACLManagerTest extends TestCase public void testACLManagerConfigurationPluginManagerACLPlugin() throws ConfigurationException { _authzManager = new ACLManager(_conf, _pluginManager, ExchangeDenier.FACTORY); - + Exchange exchange = null; assertFalse(_authzManager.authoriseDelete(_session, exchange)); } - + public void testConfigurePlugins() throws ConfigurationException { Configuration hostConfig = new PropertiesConfiguration(); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java index 317dee2b47..37a0fd7fc3 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java @@ -14,16 +14,16 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.security.access; import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.security.PrincipalHolder; public class ExchangeDenier extends AllowAll { @@ -40,9 +40,9 @@ public class ExchangeDenier extends AllowAll return new ExchangeDenier(); } }; - + @Override - public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange) + public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) { return AuthzResult.DENIED; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java index 88100dc25f..73e9dac775 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -27,14 +27,13 @@ import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.amqp_0_9.ExchangeDeclareBodyImpl; -import org.apache.qpid.framing.amqp_0_9.QueueDeclareBodyImpl; import org.apache.qpid.framing.amqp_8_0.QueueBindBodyImpl; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.DirectExchange; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.store.SkeletonMessageStore; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -43,7 +42,7 @@ public class PrincipalPermissionsTest extends TestCase private String _user = "user"; private PrincipalPermissions _perms; - + // Common things that are passed to frame constructors private AMQShortString _queueName = new AMQShortString(this.getClass().getName()+"queue"); private AMQShortString _tempQueueName = new AMQShortString(this.getClass().getName()+"tempqueue"); @@ -65,18 +64,18 @@ public class PrincipalPermissionsTest extends TestCase private AMQQueue _temporaryQueue; private Boolean _temporary = false; private Boolean _ownQueue = false; - + @Override public void setUp() { //Highlight that this test will cause a new AR to be created - ApplicationRegistry.getInstance(); + ApplicationRegistry.getInstance(); _perms = new PrincipalPermissions(_user); - try + try { PropertiesConfiguration env = new PropertiesConfiguration(); - _virtualHost = new VirtualHost(new VirtualHostConfiguration("test", env)); + _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration("test", env)); _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete); _queue = AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, _virtualHost, _arguments); _temporaryQueue = AMQQueueFactory.createAMQQueueImpl(_tempQueueName, false, _owner , true, _virtualHost, _arguments); @@ -132,27 +131,29 @@ public class PrincipalPermissionsTest extends TestCase _perms.grant(Permission.CREATEQUEUE, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); } - + // FIXME disabled, this fails due to grant putting the grant into the wrong map QPID-1598 public void disableTestExchangeCreate() { - ExchangeDeclareBodyImpl exchangeDeclare = + ExchangeDeclareBodyImpl exchangeDeclare = new ExchangeDeclareBodyImpl(_ticket, _exchangeName, _exchangeType, _passive, _durable, _autoDelete, _internal, _nowait, _arguments); Object[] authArgs = new Object[]{exchangeDeclare}; Object[] grantArgs = new Object[]{_exchangeName, _exchangeType}; - + assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs)); _perms.grant(Permission.CREATEEXCHANGE, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs)); } - + public void testConsume() { Object[] authArgs = new Object[]{_queue}; Object[] grantArgs = new Object[]{_queueName, _ownQueue}; - assertEquals(AuthzResult.DENIED,_perms.authorise(Permission.CONSUME, authArgs)); + /* FIXME: This throws a null pointer exception QPID-1599 + * assertFalse(_perms.authorise(Permission.CONSUME, authArgs)); + */ _perms.grant(Permission.CONSUME, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authArgs)); } @@ -166,7 +167,7 @@ public class PrincipalPermissionsTest extends TestCase _perms.grant(Permission.PUBLISH, grantArgs); assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgs)); } - + public void testVhostAccess() { //Tests that granting a user Virtualhost level access allows all authorisation requests diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java index 5497f0ae44..5b76bf7532 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java @@ -14,21 +14,20 @@ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations - * under the License. + * under the License. + * * - * */ package org.apache.qpid.server.security.access; import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; import org.apache.qpid.server.security.access.plugins.AllowAll; +import org.apache.qpid.server.security.PrincipalHolder; public class QueueDenier extends AllowAll { - + public static final ACLPluginFactory FACTORY = new ACLPluginFactory() { public boolean supportsTag(String name) @@ -43,18 +42,18 @@ public class QueueDenier extends AllowAll return plugin; } }; - + private String _queueName = ""; - + @Override - public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue) + public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) { if (!(queue.getName().toString().equals(_queueName))) { return AuthzResult.ALLOWED; - } - else + } + else { return AuthzResult.DENIED; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java index 5802655cfc..5169676dae 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java @@ -29,17 +29,13 @@ import org.apache.qpid.server.exchange.ExchangeType; import org.apache.qpid.server.exchange.TopicExchange; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.IncomingMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.queue.AMQPriorityQueue; -import org.apache.qpid.server.queue.SimpleAMQQueue; -import org.apache.qpid.server.queue.ExchangeBinding; -import org.apache.qpid.server.txn.NonTransactionalContext; -import org.apache.qpid.server.protocol.InternalTestProtocolSession; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; +import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.ContentHeaderBody; @@ -103,7 +99,7 @@ public class MessageStoreTest extends TestCase try { - _virtualHost = new VirtualHost(new VirtualHostConfiguration(getClass().getName(), configuration)); + _virtualHost = new VirtualHostImpl(new VirtualHostConfiguration(getClass().getName(), configuration)); ApplicationRegistry.getInstance().getVirtualHostRegistry().registerVirtualHost(_virtualHost); } catch (Exception e) @@ -169,7 +165,7 @@ public class MessageStoreTest extends TestCase Exchange topicExchange = createExchange(TopicExchange.TYPE, topicExchangeName, true); bindAllTopicQueuesToExchange(topicExchange, topicRouting); - //Send Message To NonDurable direct Exchange = persistent + //Send Message To NonDurable direct Exchange = persistent sendMessageOnExchange(nonDurableExchange, directRouting, true); // and non-persistent sendMessageOnExchange(nonDurableExchange, directRouting, false); @@ -344,22 +340,11 @@ public class MessageStoreTest extends TestCase MessagePublishInfo messageInfo = new TestMessagePublishInfo(directExchange, false, false, routingKey); - IncomingMessage currentMessage = null; + final IncomingMessage currentMessage; - try - { - currentMessage = new IncomingMessage(_virtualHost.getMessageStore().getNewMessageId(), - messageInfo, - new NonTransactionalContext(_virtualHost.getMessageStore(), - new StoreContext(), null, null), - new InternalTestProtocolSession(_virtualHost)); - } - catch (AMQException e) - { - fail(e.getMessage()); - } - currentMessage.setMessageStore(_virtualHost.getMessageStore()); + currentMessage = new IncomingMessage(messageInfo); + currentMessage.setExchange(directExchange); ContentHeaderBody headerBody = new ContentHeaderBody(); @@ -379,35 +364,42 @@ public class MessageStoreTest extends TestCase currentMessage.setExpiration(); - try - { - currentMessage.route(); - } - catch (AMQException e) - { - fail(e.getMessage()); - } + MessageMetaData mmd = currentMessage.headersReceived(); + currentMessage.setStoredMessage(_virtualHost.getMessageStore().addMessage(mmd)); + + currentMessage.route(); + - try - { - currentMessage.routingComplete(_virtualHost.getMessageStore(), new MessageHandleFactory()); - } - catch (AMQException e) - { - fail(e.getMessage()); - } // check and deliver if header says body length is zero if (currentMessage.allContentReceived()) { - try - { - currentMessage.deliverToQueues(); - } - catch (AMQException e) - { - fail(e.getMessage()); - } + // TODO Deliver to queues + ServerTransaction trans = new AutoCommitTransaction(_virtualHost.getMessageStore()); + final List<AMQQueue> destinationQueues = currentMessage.getDestinationQueues(); + trans.enqueue(currentMessage.getDestinationQueues(), currentMessage, new ServerTransaction.Action() { + public void postCommit() + { + try + { + AMQMessage message = new AMQMessage(currentMessage.getStoredMessage()); + + for(AMQQueue queue : destinationQueues) + { + QueueEntry entry = queue.enqueue(message); + } + } + catch (AMQException e) + { + e.printStackTrace(); + } + } + + public void onRollback() + { + //To change body of implemented methods use File | Settings | File Templates. + } + }); } } @@ -496,14 +488,7 @@ public class MessageStoreTest extends TestCase fail(e.getMessage()); } - try - { - _virtualHost.getQueueRegistry().registerQueue(queue); - } - catch (AMQException e) - { - fail(e.getMessage()); - } + _virtualHost.getQueueRegistry().registerQueue(queue); } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java index fd6789f5ce..9c12242a07 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java @@ -25,14 +25,15 @@ import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.logging.LogSubject; import java.util.List; import java.util.concurrent.atomic.AtomicLong; +import java.nio.ByteBuffer; /** * A message store that does nothing. Designed to be used in tests that do not want to use any message store @@ -45,8 +46,19 @@ public class SkeletonMessageStore implements MessageStore public void configure(String base, Configuration config) throws Exception { } - - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception { //To change body of implemented methods use File | Settings | File Templates. } @@ -55,7 +67,12 @@ public class SkeletonMessageStore implements MessageStore { } - public void removeMessage(StoreContext s, Long messageId) + public <M extends StorableMessageMetaData> StoredMessage<M> addMessage(M metaData) + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeMessage(Long messageId) { } @@ -85,24 +102,10 @@ public class SkeletonMessageStore implements MessageStore public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException { - } - - public void beginTran(StoreContext s) throws AMQException - { } - public boolean inTran(StoreContext sc) - { - return false; - } - public void commitTran(StoreContext storeContext) throws AMQException - { - } - public void abortTran(StoreContext storeContext) throws AMQException - { - } public List<AMQQueue> createQueues() throws AMQException { @@ -114,22 +117,26 @@ public class SkeletonMessageStore implements MessageStore return _messageId.getAndIncrement(); } - public void storeContentBodyChunk(StoreContext sc, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException + public void storeContentBodyChunk( + Long messageId, + int index, + ContentChunk contentBody, + boolean lastContentBody) throws AMQException { } - public void storeMessageMetaData(StoreContext sc, Long messageId, MessageMetaData messageMetaData) throws AMQException + public void storeMessageMetaData(Long messageId, MessageMetaData messageMetaData) throws AMQException { } - public MessageMetaData getMessageMetaData(StoreContext s,Long messageId) throws AMQException + public MessageMetaData getMessageMetaData(Long messageId) throws AMQException { return null; } - public ContentChunk getContentBodyChunk(StoreContext s,Long messageId, int index) throws AMQException + public ContentChunk getContentBodyChunk(Long messageId, int index) throws AMQException { return null; } @@ -139,18 +146,75 @@ public class SkeletonMessageStore implements MessageStore return false; } - public void removeQueue(final AMQQueue queue) throws AMQException + public void storeMessageHeader(Long messageNumber, ServerMessage message) { + //To change body of implemented methods use File | Settings | File Templates. + } + public void storeContent(Long messageNumber, long offset, ByteBuffer body) + { + //To change body of implemented methods use File | Settings | File Templates. } - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public ServerMessage getMessage(Long messageNumber) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void removeQueue(final AMQQueue queue) throws AMQException + { + + } + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, + LogSubject logSubject) throws Exception + { + //To change body of implemented methods use File | Settings | File Templates. } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + public Transaction newTransaction() { + return new Transaction() + { + + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void commitTran() throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + public StoreFuture commitTranAsync() throws AMQException + { + return new StoreFuture() + { + public boolean isComplete() + { + return true; + } + + public void waitForCompletion() + { + + } + }; + } + + public void abortTran() throws AMQException + { + //To change body of implemented methods use File | Settings | File Templates. + } + }; } + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java index 4e48435962..4dea13d391 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java @@ -20,32 +20,79 @@ */ package org.apache.qpid.server.store; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.framing.abstraction.ContentChunk; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.List; +import java.nio.ByteBuffer; /** * Adds some extra methods to the memory message store for testing purposes. */ public class TestMemoryMessageStore extends MemoryMessageStore { + private AtomicInteger _messageCount = new AtomicInteger(0); + + public TestMemoryMessageStore() { - _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>(); - _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>(); } - public ConcurrentMap<Long, MessageMetaData> getMessageMetaDataMap() + @Override + public StoredMessage addMessage(StorableMessageMetaData metaData) { - return _metaDataMap; + return new TestableStoredMessage(super.addMessage(metaData)); } - public ConcurrentMap<Long, List<ContentChunk>> getContentBodyMap() + public int getMessageCount() { - return _contentBodyMap; + return _messageCount.get(); + } + + private class TestableStoredMessage implements StoredMessage + { + private final StoredMessage _storedMessage; + + public TestableStoredMessage(StoredMessage storedMessage) + { + _messageCount.incrementAndGet(); + _storedMessage = storedMessage; + } + + public StorableMessageMetaData getMetaData() + { + return _storedMessage.getMetaData(); + } + + public long getMessageNumber() + { + return _storedMessage.getMessageNumber(); + } + + public void addContent(int offsetInMessage, ByteBuffer src) + { + _storedMessage.addContent(offsetInMessage, src); + } + + public int getContent(int offsetInMessage, ByteBuffer dst) + { + return _storedMessage.getContent(offsetInMessage, dst); + } + + public StoreFuture flushToStore() + { + return _storedMessage.flushToStore(); + } + + public void remove() + { + _storedMessage.remove(); + _messageCount.decrementAndGet(); + } + } + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java index 2346660d25..c5b1ba7868 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java @@ -26,9 +26,8 @@ import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.queue.AMQMessage; -import org.apache.qpid.server.queue.MessageHandleFactory; -import org.apache.qpid.server.queue.AMQMessageHandle; +import org.apache.qpid.server.message.AMQMessage; +import org.apache.qpid.server.message.MessageMetaData; /** * Tests that reference counting works correctly with AMQMessage and the message store @@ -37,13 +36,12 @@ public class TestReferenceCounting extends TestCase { private TestMemoryMessageStore _store; - private StoreContext _storeContext = new StoreContext(); - protected void setUp() throws Exception { super.setUp(); _store = new TestMemoryMessageStore(); + } /** @@ -83,11 +81,12 @@ public class TestReferenceCounting extends TestCase }; - final long messageId = _store.getNewMessageId(); - AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true); - messageHandle.setPublishAndContentHeaderBody(_storeContext,info, chb); - AMQMessage message = new AMQMessage(messageHandle, - _storeContext,info); + + MessageMetaData mmd = new MessageMetaData(info, chb, 0); + StoredMessage storedMessage = _store.addMessage(mmd); + + + AMQMessage message = new AMQMessage(storedMessage); message = message.takeReference(); @@ -95,9 +94,9 @@ public class TestReferenceCounting extends TestCase // message.routingComplete(_store, _storeContext, new MessageHandleFactory()); - assertEquals(1, _store.getMessageMetaDataMap().size()); - message.decrementReference(_storeContext); - assertEquals(1, _store.getMessageMetaDataMap().size()); + assertEquals(1, _store.getMessageCount()); + message.decrementReference(); + assertEquals(1, _store.getMessageCount()); } private ContentHeaderBody createPersistentContentHeader() @@ -141,25 +140,24 @@ public class TestReferenceCounting extends TestCase } }; - final Long messageId = _store.getNewMessageId(); final ContentHeaderBody chb = createPersistentContentHeader(); - AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true); - messageHandle.setPublishAndContentHeaderBody(_storeContext,info,chb); - AMQMessage message = new AMQMessage(messageHandle, - _storeContext, - info); - - + + MessageMetaData mmd = new MessageMetaData(info, chb, 0); + StoredMessage storedMessage = _store.addMessage(mmd); + + AMQMessage message = new AMQMessage(storedMessage); + + message = message.takeReference(); // we call routing complete to set up the handle // message.routingComplete(_store, _storeContext, new MessageHandleFactory()); - assertEquals(1, _store.getMessageMetaDataMap().size()); + assertEquals(1, _store.getMessageCount()); message = message.takeReference(); - message.decrementReference(_storeContext); - assertEquals(1, _store.getMessageMetaDataMap().size()); + message.decrementReference(); + assertEquals(1, _store.getMessageCount()); } public static junit.framework.Test suite() diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java index 9146fe88ae..ab8c1e7c9c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java @@ -22,14 +22,15 @@ package org.apache.qpid.server.store; import org.apache.qpid.AMQException; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; -import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.framing.abstraction.ContentChunk; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; import java.util.List; +import java.nio.ByteBuffer; /** * Adds some extra methods to the memory message store for testing purposes. @@ -39,6 +40,7 @@ public class TestableMemoryMessageStore extends MemoryMessageStore MemoryMessageStore _mms = null; private HashMap<Long, AMQQueue> _messages = new HashMap<Long, AMQQueue>(); + private AtomicInteger _messageCount = new AtomicInteger(0); public TestableMemoryMessageStore(MemoryMessageStore mms) { @@ -47,46 +49,111 @@ public class TestableMemoryMessageStore extends MemoryMessageStore public TestableMemoryMessageStore() { - _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>(); - _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>(); + + } + + + + + @Override + public StoredMessage addMessage(StorableMessageMetaData metaData) + { + return new TestableStoredMessage(super.addMessage(metaData)); + } + + public int getMessageCount() + { + return _messageCount.get(); } - public ConcurrentMap<Long, MessageMetaData> getMessageMetaDataMap() + private class TestableTransaction implements Transaction { - if (_mms != null) + public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQException { - return _mms._metaDataMap; + getMessages().put(messageId, (AMQQueue)queue); } - else + + public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQException { - return _metaDataMap; + getMessages().remove(messageId); } - } - public ConcurrentMap<Long, List<ContentChunk>> getContentBodyMap() - { - if (_mms != null) + public void commitTran() throws AMQException { - return _mms._contentBodyMap; } - else + + public StoreFuture commitTranAsync() throws AMQException + { + return new StoreFuture() + { + public boolean isComplete() + { + return true; + } + + public void waitForCompletion() + { + + } + }; + } + + public void abortTran() throws AMQException { - return _contentBodyMap; } - } - - public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException - { - getMessages().put(messageId, queue); } - public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException + + @Override + public Transaction newTransaction() { - getMessages().remove(messageId); + return new TestableTransaction(); } public HashMap<Long, AMQQueue> getMessages() { return _messages; } + + private class TestableStoredMessage implements StoredMessage + { + private final StoredMessage _storedMessage; + + public TestableStoredMessage(StoredMessage storedMessage) + { + _messageCount.incrementAndGet(); + _storedMessage = storedMessage; + } + + public StorableMessageMetaData getMetaData() + { + return _storedMessage.getMetaData(); + } + + public long getMessageNumber() + { + return _storedMessage.getMessageNumber(); + } + + public void addContent(int offsetInMessage, ByteBuffer src) + { + _storedMessage.addContent(offsetInMessage, src); + } + + public int getContent(int offsetInMessage, ByteBuffer dst) + { + return _storedMessage.getContent(offsetInMessage, dst); + } + + public StoreFuture flushToStore() + { + return _storedMessage.flushToStore(); + } + + public void remove() + { + _storedMessage.remove(); + _messageCount.decrementAndGet(); + } + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java index a3274a3a05..97ba143bdf 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java @@ -42,11 +42,15 @@ public class MockSubscription implements Subscription private AMQShortString tag = new AMQShortString("mocktag"); private AMQQueue queue = null; private StateListener _listener = null; - private QueueEntry lastSeen = null; + private AMQQueue.Context _queueContext = null; private State _state = State.ACTIVE; private ArrayList<QueueEntry> messages = new ArrayList<QueueEntry>(); private final Lock _stateChangeLock = new ReentrantLock(); + private final QueueEntry.SubscriptionAcquiredState _owningState = new QueueEntry.SubscriptionAcquiredState(this); + private final QueueEntry.SubscriptionAssignedState _assignedState = new QueueEntry.SubscriptionAssignedState(this); + + private static final AtomicLong idGenerator = new AtomicLong(0); // Create a simple ID that increments for ever new Subscription private final long _subscriptionID = idGenerator.getAndIncrement(); @@ -81,14 +85,19 @@ public class MockSubscription implements Subscription return _subscriptionID; } - public QueueEntry getLastSeenEntry() + public AMQQueue.Context getQueueContext() { - return lastSeen; + return _queueContext; } public SubscriptionAcquiredState getOwningState() { - return new QueueEntry.SubscriptionAcquiredState(this); + return _owningState; + } + + public QueueEntry.SubscriptionAssignedState getAssignedState() + { + return _assignedState; } public LogActor getLogActor() @@ -116,6 +125,21 @@ public class MockSubscription implements Subscription return true; } + public void confirmAutoClose() + { + + } + + public void set(String key, Object value) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public Object get(String key) + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public boolean isAutoClose() { return false; @@ -131,6 +155,16 @@ public class MockSubscription implements Subscription return _closed; } + public boolean acquires() + { + return true; + } + + public boolean seesRequeues() + { + return true; + } + public boolean isSuspended() { return false; @@ -149,25 +183,23 @@ public class MockSubscription implements Subscription { } + public void onDequeue(QueueEntry queueEntry) + { + } + public void restoreCredit(QueueEntry queueEntry) { + //To change body of implemented methods use File | Settings | File Templates. } public void send(QueueEntry msg) throws AMQException { - lastSeen = msg; messages.add(msg); } - public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue) + public void setQueueContext(AMQQueue.Context queueContext) { - boolean result = false; - if (expected != null) - { - result = (expected.equals(lastSeen)); - } - lastSeen = newValue; - return result; + _queueContext = queueContext; } public void setQueue(AMQQueue queue, boolean exclusive) @@ -175,6 +207,10 @@ public class MockSubscription implements Subscription this.queue = queue; } + public void setNoLocal(boolean noLocal) + { + } + public void setStateListener(StateListener listener) { this._listener = listener; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java deleted file mode 100644 index 84d3d313d1..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.txn; - -import junit.framework.TestCase; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.TestMemoryMessageStore; -import org.apache.qpid.server.store.StoreContext; - -import java.util.LinkedList; -import java.util.NoSuchElementException; - -public class TxnBufferTest extends TestCase -{ - private final LinkedList<MockOp> ops = new LinkedList<MockOp>(); - - public void testCommit() throws AMQException - { - MockStore store = new MockStore(); - - TxnBuffer buffer = new TxnBuffer(); - buffer.enlist(new MockOp().expectPrepare().expectCommit()); - //check relative ordering - MockOp op = new MockOp().expectPrepare().expectPrepare().expectCommit().expectCommit(); - buffer.enlist(op); - buffer.enlist(op); - buffer.enlist(new MockOp().expectPrepare().expectCommit()); - - buffer.commit(null); - - validateOps(); - store.validate(); - } - - public void testRollback() throws AMQException - { - MockStore store = new MockStore(); - - TxnBuffer buffer = new TxnBuffer(); - buffer.enlist(new MockOp().expectRollback()); - buffer.enlist(new MockOp().expectRollback()); - buffer.enlist(new MockOp().expectRollback()); - - buffer.rollback(null); - - validateOps(); - store.validate(); - } - - public void testCommitWithFailureDuringPrepare() throws AMQException - { - MockStore store = new MockStore(); - store.beginTran(null); - - TxnBuffer buffer = new TxnBuffer(); - buffer.enlist(new StoreMessageOperation(store)); - buffer.enlist(new MockOp().expectPrepare().expectUndoPrepare()); - buffer.enlist(new TxnTester(store)); - buffer.enlist(new MockOp().expectPrepare().expectUndoPrepare()); - buffer.enlist(new FailedPrepare()); - buffer.enlist(new MockOp()); - - try - { - buffer.commit(null); - } - catch (NoSuchElementException e) - { - - } - - validateOps(); - store.validate(); - } - - public void testCommitWithPersistance() throws AMQException - { - MockStore store = new MockStore(); - store.beginTran(null); - store.expectCommit(); - - TxnBuffer buffer = new TxnBuffer(); - buffer.enlist(new MockOp().expectPrepare().expectCommit()); - buffer.enlist(new MockOp().expectPrepare().expectCommit()); - buffer.enlist(new MockOp().expectPrepare().expectCommit()); - buffer.enlist(new StoreMessageOperation(store)); - buffer.enlist(new TxnTester(store)); - - buffer.commit(null); - validateOps(); - store.validate(); - } - - private void validateOps() - { - for (MockOp op : ops) - { - op.validate(); - } - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(TxnBufferTest.class); - } - - class MockOp implements TxnOp - { - final Object PREPARE = "PREPARE"; - final Object COMMIT = "COMMIT"; - final Object UNDO_PREPARE = "UNDO_PREPARE"; - final Object ROLLBACK = "ROLLBACK"; - - private final LinkedList expected = new LinkedList(); - - MockOp() - { - ops.add(this); - } - - public void prepare(StoreContext context) - { - assertEquals(expected.removeLast(), PREPARE); - } - - public void commit(StoreContext context) - { - assertEquals(expected.removeLast(), COMMIT); - } - - public void undoPrepare() - { - assertEquals(expected.removeLast(), UNDO_PREPARE); - } - - public void rollback(StoreContext context) - { - assertEquals(expected.removeLast(), ROLLBACK); - } - - private MockOp expect(Object optype) - { - expected.addFirst(optype); - return this; - } - - MockOp expectPrepare() - { - return expect(PREPARE); - } - - MockOp expectCommit() - { - return expect(COMMIT); - } - - MockOp expectUndoPrepare() - { - return expect(UNDO_PREPARE); - } - - MockOp expectRollback() - { - return expect(ROLLBACK); - } - - void validate() - { - assertEquals("Expected ops were not all invoked", new LinkedList(), expected); - } - - void clear() - { - expected.clear(); - } - } - - class MockStore extends TestMemoryMessageStore - { - final Object BEGIN = "BEGIN"; - final Object ABORT = "ABORT"; - final Object COMMIT = "COMMIT"; - - private final LinkedList expected = new LinkedList(); - private boolean inTran; - - public void beginTran(StoreContext context) throws AMQException - { - inTran = true; - } - - public void commitTran(StoreContext context) throws AMQException - { - assertEquals(expected.removeLast(), COMMIT); - inTran = false; - } - - public void abortTran(StoreContext context) throws AMQException - { - assertEquals(expected.removeLast(), ABORT); - inTran = false; - } - - public boolean inTran(StoreContext context) - { - return inTran; - } - - private MockStore expect(Object optype) - { - expected.addFirst(optype); - return this; - } - - MockStore expectBegin() - { - return expect(BEGIN); - } - - MockStore expectCommit() - { - return expect(COMMIT); - } - - MockStore expectAbort() - { - return expect(ABORT); - } - - void clear() - { - expected.clear(); - } - - void validate() - { - assertEquals("Expected ops were not all invoked", new LinkedList(), expected); - } - } - - class NullOp implements TxnOp - { - public void prepare(StoreContext context) throws AMQException - { - } - public void commit(StoreContext context) - { - } - public void undoPrepare() - { - } - public void rollback(StoreContext context) - { - } - } - - class FailedPrepare extends NullOp - { - public void prepare() throws AMQException - { - throw new AMQException(null, "Fail!", null); - } - } - - class TxnTester extends NullOp - { - private final MessageStore store; - - private final StoreContext context = new StoreContext(); - - TxnTester(MessageStore store) - { - this.store = store; - } - - public void prepare() throws AMQException - { - assertTrue("Expected prepare to be performed under txn", store.inTran(context)); - } - - public void commit() - { - assertTrue("Expected commit not to be performed under txn", !store.inTran(context)); - } - } - -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java index f2096df9d1..906c769f9c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java @@ -31,7 +31,6 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.ConsumerTagNotUniqueException; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.exchange.Exchange; @@ -41,12 +40,10 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.StoreContext; import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.util.MockChannel; -import java.security.Principal; public class InternalBrokerBaseCase extends TestCase { @@ -55,7 +52,6 @@ public class InternalBrokerBaseCase extends TestCase protected MockChannel _channel; protected InternalTestProtocolSession _session; protected VirtualHost _virtualHost; - protected StoreContext _storeContext = new StoreContext(); protected AMQQueue _queue; protected AMQShortString QUEUE_NAME; @@ -97,7 +93,7 @@ public class InternalBrokerBaseCase extends TestCase protected void checkStoreContents(int messageCount) { - assertEquals("Message header count incorrect in the MetaDataMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getMessageMetaDataMap().size()); + assertEquals("Message header count incorrect in the MetaDataMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getMessageCount()); //The above publish message is sufficiently small not to fit in the header so no Body is required. //assertEquals("Message body count incorrect in the ContentBodyMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getContentBodyMap().size()); @@ -114,11 +110,7 @@ public class InternalBrokerBaseCase extends TestCase e.printStackTrace(); fail(e.getMessage()); } - catch (ConsumerTagNotUniqueException e) - { - e.printStackTrace(); - fail(e.getMessage()); - } + //Keep the compiler happy return null; } @@ -137,11 +129,7 @@ public class InternalBrokerBaseCase extends TestCase e.printStackTrace(); fail(e.getMessage()); } - catch (ConsumerTagNotUniqueException e) - { - e.printStackTrace(); - fail(e.getMessage()); - } + //Keep the compiler happy return null; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 6b8201eefb..3d37412376 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -36,8 +36,9 @@ import org.apache.qpid.server.security.access.ACLManager; import org.apache.qpid.server.security.access.plugins.AllowAll; import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; +import org.apache.qpid.server.virtualhost.VirtualHost; import java.util.Arrays; import java.util.Collection; @@ -76,7 +77,7 @@ public class NullApplicationRegistry extends ApplicationRegistry _virtualHostRegistry = new VirtualHostRegistry(this); PropertiesConfiguration vhostProps = new PropertiesConfiguration(); VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); - VirtualHost dummyHost = new VirtualHost(hostConfig); + VirtualHost dummyHost = new VirtualHostImpl(hostConfig); _virtualHostRegistry.registerVirtualHost(dummyHost); _virtualHostRegistry.setDefaultVirtualHostName("test"); _pluginManager = new PluginManager(""); @@ -97,7 +98,7 @@ public class NullApplicationRegistry extends ApplicationRegistry try { - super.close(); + super.close(); } finally { diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java index 7b7c86bb80..bb338458f1 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -35,8 +35,9 @@ import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabase import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStore; -import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; +import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.logging.RootMessageLoggerImpl; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.TestLogActor; @@ -60,7 +61,7 @@ public class TestApplicationRegistry extends ApplicationRegistry private ServerConfiguration _config; - + public TestApplicationRegistry() throws ConfigurationException { super(new ServerConfiguration(new PropertiesConfiguration())); @@ -96,10 +97,10 @@ public class TestApplicationRegistry extends ApplicationRegistry _messageStore = new TestableMemoryMessageStore(); _virtualHostRegistry = new VirtualHostRegistry(this); - + PropertiesConfiguration vhostProps = new PropertiesConfiguration(); VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps); - _vHost = new VirtualHost(hostConfig, _messageStore); + _vHost = new VirtualHostImpl(hostConfig, _messageStore); _virtualHostRegistry.registerVirtualHost(_vHost); @@ -152,7 +153,7 @@ public class TestApplicationRegistry extends ApplicationRegistry CurrentActor.remove(); } } - + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java b/qpid/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java index 447d09429d..9bd1e7c5e1 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java @@ -35,9 +35,6 @@ public class MockChannel extends AMQChannel super(session, channelId, messageStore); } - public Subscription getSubscription(AMQShortString subscription) - { - return _tag2SubscriptionMap.get(subscription); - } - + + } diff --git a/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java b/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java index ea0946f6d6..2efb22610f 100644 --- a/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java +++ b/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java @@ -108,6 +108,8 @@ public class GenerateLogMessages createMessageClass("ManagementConsole", "MNG"); createMessageClass("VirtualHost", "VHT"); createMessageClass("MessageStore", "MST"); + createMessageClass("ConfigStore", "CFG"); + createMessageClass("TransactionLog", "TXN"); createMessageClass("Connection", "CON"); createMessageClass("Channel", "CHN"); createMessageClass("Queue", "QUE"); @@ -465,4 +467,4 @@ public class GenerateLogMessages super(message); } } -}
\ No newline at end of file +} diff --git a/qpid/java/build.deps b/qpid/java/build.deps index 709f2a478e..464afdc136 100644 --- a/qpid/java/build.deps +++ b/qpid/java/build.deps @@ -82,7 +82,7 @@ tools.libs=${client.libs} broker.libs=${common.libs} ${commons-cli} ${commons-logging} ${log4j} \ ${slf4j-log4j} ${xalan} ${felix.libs} ${derby-db} -broker-plugins.libs=${common.libs} ${felix.libs} +broker-plugins.libs=${common.libs} ${felix.libs} ${log4j} management-client.libs=${jsp.libs} ${log4j} ${slf4j-log4j} ${slf4j-api} ${commons-pool} ${geronimo-servlet} ${muse.libs} ${javassist} ${xalan} ${mina-core} ${mina-filter-ssl} management-agent.libs=${client.libs} ${commons-logging} ${geronimo-jms} diff --git a/qpid/java/client/build.xml b/qpid/java/client/build.xml index 73252ac124..3c6132dc5b 100644 --- a/qpid/java/client/build.xml +++ b/qpid/java/client/build.xml @@ -20,7 +20,8 @@ --> <project name="AMQ Client" default="build"> - <property name="module.depends" value="common common/test"/> + <property name="module.depends" value="common"/> + <property name="module.test.depends" value="common/test" /> <property name="module.genpom" value="true"/> <property name="module.genpom.args" value="-Sgeronimo-jms_1.1_spec=provided"/> diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java index ed122a772e..b57c834598 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java @@ -214,14 +214,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect if ((id & FAST_CHANNEL_ACCESS_MASK) == 0) { done = (_fastAccessSessions[id] == null); - } + } else { done = (!_slowAccessSessions.keySet().contains(id)); } } } - + return id; } @@ -320,11 +320,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect //Indicates whether we need to sync on every message ack private boolean _syncAck; - + //Indicates the sync publish options (persistent|all) //By default it's async publish - private String _syncPublish = ""; - + private String _syncPublish = ""; + /** * @param broker brokerdetails * @param username username @@ -418,7 +418,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect if (connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PERSISTENCE) != null) { - _syncPersistence = + _syncPersistence = Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.OPTIONS_SYNC_PERSISTENCE)); _logger.warn("sync_persistence is a deprecated property, " + "please use sync_publish={persistent|all} instead"); @@ -453,10 +453,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect // use the default value set for all connections _syncPublish = System.getProperty((ClientProperties.SYNC_ACK_PROP_NAME),_syncPublish); } - + + String amqpVersion = System.getProperty((ClientProperties.AMQP_VERSION), "0-10"); + _failoverPolicy = new FailoverPolicy(connectionURL, this); BrokerDetails brokerDetails = _failoverPolicy.getCurrentBrokerDetails(); - if (brokerDetails.getTransport().equals(BrokerDetails.VM)) + if (brokerDetails.getTransport().equals(BrokerDetails.VM) || "0-8".equals(amqpVersion) || "0-9".equals(amqpVersion)) { _delegate = new AMQConnectionDelegate_8_0(this); } @@ -538,7 +540,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } else if (!_connected) { - retryAllowed = _failoverPolicy.failoverAllowed(); + retryAllowed = _failoverPolicy.failoverAllowed(); brokerDetails = _failoverPolicy.getNextBrokerDetails(); } } @@ -591,7 +593,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect throw new AMQConnectionFailureException(message, connectionException); } - + _connectionMetaData = new QpidConnectionMetaData(this); } @@ -1573,7 +1575,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { return _syncPersistence; } - + /** * Indicates whether we need to sync on every message ack */ @@ -1581,12 +1583,12 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { return _syncAck; } - + public String getSyncPublish() { return _syncPublish; } - + public void setIdleTimeout(long l) { _delegate.setIdleTimeout(l); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java index 97d0d0516e..e1d9ae735c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java @@ -89,11 +89,11 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate StateWaiter waiter = _conn._protocolHandler.createWaiter(openOrClosedStates); // TODO: use system property thingy for this - if (System.getProperty("UseTransportIo", "false").equals("false")) + if (System.getProperty("UseTransportIo", "false").equals("false")) { TransportConnection.getInstance(brokerDetail).connect(_conn._protocolHandler, brokerDetail); - } - else + } + else { _conn.getProtocolHandler().createIoTransportSession(brokerDetail); } @@ -197,7 +197,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate * Low = MaxPrefetch / 2 * @return XASession * @throws JMSException thrown if there is a problem creating the session. - */ + */ public XASession createXASession() throws JMSException { return createXASession((int) _conn.getMaxPrefetch(), (int) _conn.getMaxPrefetch() / 2); @@ -214,7 +214,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate // todo Be aware of possible changes to parameter order as versions change. BasicQosBody basicQosBody = _conn.getProtocolHandler().getMethodRegistry().createBasicQosBody(0,prefetchHigh,false); _conn._protocolHandler.syncWrite(basicQosBody.generateFrame(channelId),BasicQosOkBody.class); - + if (transacted) { if (_logger.isDebugEnabled()) @@ -222,7 +222,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate _logger.debug("Issuing TxSelect for " + channelId); } TxSelectBody body = _conn.getProtocolHandler().getMethodRegistry().createTxSelectBody(); - + // TODO: Be aware of possible changes to parameter order as versions change. _conn._protocolHandler.syncWrite(body.generateFrame(channelId), TxSelectOkBody.class); } @@ -299,7 +299,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate } } } - + public void setIdleTimeout(long l){} public int getMaxChannelID() diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java index 1587d6a6bf..2324d441cc 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java @@ -468,7 +468,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic public boolean isQueueBound(final AMQShortString exchangeName, final AMQShortString queueName, final AMQShortString routingKey,AMQShortString[] bindingKeys) throws JMSException { - String rk = ""; + String rk = null; boolean res; if (bindingKeys != null && bindingKeys.length>0) { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java index 44ce59975a..df59be25d0 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java @@ -46,14 +46,14 @@ import org.slf4j.LoggerFactory; public abstract class BasicMessageProducer extends Closeable implements org.apache.qpid.jms.MessageProducer { - enum PublishMode { ASYNC_PUBLISH_ALL, SYNC_PUBLISH_PERSISTENT, SYNC_PUBLISH_ALL }; - + enum PublishMode { ASYNC_PUBLISH_ALL, SYNC_PUBLISH_PERSISTENT, SYNC_PUBLISH_ALL }; + protected final Logger _logger = LoggerFactory.getLogger(getClass()); private AMQConnection _connection; /** - * If true, messages will not get a timestamp. + * If true, messages will not get a timestamp. */ protected boolean _disableTimestamps; @@ -105,7 +105,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac private long _producerId; /** - * The session used to create this producer + * The session used to create this producer */ protected AMQSession _session; @@ -118,11 +118,11 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac private boolean _disableMessageId; private UUIDGen _messageIdGenerator = UUIDs.newGenerator(); - + protected String _userID; // ref user id used in the connection. private static final ContentBody[] NO_CONTENT_BODIES = new ContentBody[0]; - + protected PublishMode publishMode = PublishMode.ASYNC_PUBLISH_ALL; protected BasicMessageProducer(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId, @@ -145,14 +145,14 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac _mandatory = mandatory; _waitUntilSent = waitUntilSent; _userID = connection.getUsername(); - setPublishMode(); + setPublishMode(); } - + void setPublishMode() { // Publish mode could be configured at destination level as well. // Will add support for this when we provide a more robust binding URL - + String syncPub = _connection.getSyncPublish(); // Support for deprecated option sync_persistence if (syncPub.equals("persistent") || _connection.getSyncPersistence()) @@ -163,7 +163,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac { publishMode = PublishMode.SYNC_PUBLISH_ALL; } - + _logger.info("MessageProducer " + toString() + " using publish mode : " + publishMode); } @@ -277,6 +277,7 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac checkPreConditions(); checkInitialDestination(); + synchronized (_connection.getFailoverMutex()) { sendImpl(_destination, message, _deliveryMode, _messagePriority, _timeToLive, _mandatory, _immediate); @@ -548,6 +549,10 @@ public abstract class BasicMessageProducer extends Closeable implements org.apac { throw new javax.jms.IllegalStateException("Invalid Session"); } + if(_session.getAMQConnection().isClosed()) + { + throw new javax.jms.IllegalStateException("Connection closed"); + } } private void checkInitialDestination() diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java b/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java index be0d283470..e5050b4fbd 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/configuration/ClientProperties.java @@ -33,7 +33,7 @@ public class ClientProperties public static final String IGNORE_SET_CLIENTID_PROP_NAME = "ignore_setclientID"; /** - * This property is currently used within the 0.10 code path only + * This property is currently used within the 0.10 code path only * The maximum number of pre-fetched messages per destination * This property is used for all the connection unless it is overwritten by the connectionURL * type: long @@ -46,13 +46,13 @@ public class ClientProperties * type: boolean */ public static final String SYNC_PERSISTENT_PROP_NAME = "sync_persistence"; - + /** * When true a sync command is sent after sending a message ack. * type: boolean */ public static final String SYNC_ACK_PROP_NAME = "sync_ack"; - + /** * sync_publish property - {persistent|all} * If set to 'persistent',then persistent messages will be publish synchronously @@ -60,17 +60,17 @@ public class ClientProperties * published synchronously. */ public static final String SYNC_PUBLISH_PROP_NAME = "sync_publish"; - + /** * This value will be used in the following settings * To calculate the SO_TIMEOUT option of the socket (2*idle_timeout) * If this values is between the max and min values specified for heartbeat * by the broker in TuneOK it will be used as the heartbeat interval. - * If not a warning will be printed and the max value specified for + * If not a warning will be printed and the max value specified for * heartbeat in TuneOK will be used */ public static final String IDLE_TIMEOUT_PROP_NAME = "idle_timeout"; - + /** * ========================================================== @@ -100,4 +100,6 @@ public class ClientProperties */ public static final String WRITE_BUFFER_LIMIT_PROP_NAME = "qpid.read.buffer.limit"; public static final String WRITE_BUFFER_LIMIT_DEFAULT = "262144"; + + public static final String AMQP_VERSION = "qpid.amqp.version"; } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java index 190776891e..f74dbba939 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java @@ -21,7 +21,6 @@ package org.apache.qpid.client.failover; import org.apache.qpid.AMQDisconnectedException; -import org.apache.qpid.AMQException; import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.client.state.AMQStateManager; import org.apache.qpid.client.state.AMQState; @@ -94,7 +93,6 @@ public class FailoverHandler implements Runnable * Creates a failover handler on a protocol session, for a particular MINA session (network connection). * * @param amqProtocolHandler The protocol handler that spans the failover. - * @param session The MINA session, for the failing connection. */ public FailoverHandler(AMQProtocolHandler amqProtocolHandler) { @@ -135,10 +133,12 @@ public class FailoverHandler implements Runnable // have a state waiter waiting until the connection is closed for some reason. Or in future we may have // a slightly more complex state model therefore I felt it was worthwhile doing this. AMQStateManager existingStateManager = _amqProtocolHandler.getStateManager(); - + + // Use a fresh new StateManager for the reconnection attempts _amqProtocolHandler.setStateManager(new AMQStateManager()); + if (!_amqProtocolHandler.getConnection().firePreFailover(_host != null)) { _logger.info("Failover process veto-ed by client"); @@ -190,7 +190,7 @@ public class FailoverHandler implements Runnable } else { - // Set the new Protocol Session in the StateManager. + // Set the new Protocol Session in the StateManager. existingStateManager.setProtocolSession(_amqProtocolHandler.getProtocolSession()); // Now that the ProtocolHandler has been reconnected clean up @@ -198,7 +198,7 @@ public class FailoverHandler implements Runnable // it any old exception that had occured prior to failover may // prohibit reconnection. // e.g. During testing when the broker is shutdown gracefully. - // The broker + // The broker // Clear any exceptions we gathered if (existingStateManager.getCurrentState() != AMQState.CONNECTION_OPEN) { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java index 35bc521c80..6500a82818 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java @@ -110,10 +110,6 @@ import org.slf4j.LoggerFactory; * <tr><td> * </table> * - * @todo Explain the system property: amqj.shared_read_write_pool. How does putting the protocol codec filter before the - * async write filter make it a shared pool? The pooling filter uses the same thread pool for reading and writing - * anyway, see {@link org.apache.qpid.pool.PoolingFilter}, docs for comments. Will putting the protocol codec - * filter before it mean not doing the read/write asynchronously but in the main filter thread? * @todo Use a single handler instance, by shifting everything to do with the 'protocol session' state, including * failover state, into AMQProtocolSession, and tracking that from AMQConnection? The lifecycles of * AMQProtocolSesssion and AMQConnection will be the same, so if there is high cohesion between them, they could @@ -172,10 +168,10 @@ public class AMQProtocolHandler implements ProtocolEngine private Job _writeJob; private ReferenceCountingExecutorService _poolReference = ReferenceCountingExecutorService.getInstance(); private NetworkDriver _networkDriver; - + private long _writtenBytes; private long _readBytes; - + /** * Creates a new protocol handler, associated with the specified client connection instance. * @@ -215,10 +211,6 @@ public class AMQProtocolHandler implements ProtocolEngine * process will be started, provided that it is the clients policy to allow failover, and provided that a failover * has not already been started or failed. * - * <p/>It is important to note that when the connection dies this method may be called or {@link #exceptionCaught} - * may be called first followed by this method. This depends on whether the client was trying to send data at the - * time of the failure. - * * @todo Clarify: presumably exceptionCaught is called when the client is sending during a connection failure and * not otherwise? The above comment doesn't make that clear. */ @@ -261,7 +253,7 @@ public class AMQProtocolHandler implements ProtocolEngine { _logger.debug("sessionClose() not allowed to failover"); _connection.exceptionReceived(new AMQDisconnectedException( - "Server closed connection and reconnection " + "not permitted.", + "Server closed connection and reconnection " + "not permitted.", _stateManager.getLastException())); } else @@ -277,12 +269,15 @@ public class AMQProtocolHandler implements ProtocolEngine /** See {@link FailoverHandler} to see rationale for separate thread. */ private void startFailoverThread() { - Thread failoverThread = new Thread(_failoverHandler); - failoverThread.setName("Failover"); - // Do not inherit daemon-ness from current thread as this can be a daemon - // thread such as a AnonymousIoService thread. - failoverThread.setDaemon(false); - failoverThread.start(); + if(!_connection.isClosed()) + { + Thread failoverThread = new Thread(_failoverHandler); + failoverThread.setName("Failover"); + // Do not inherit daemon-ness from current thread as this can be a daemon + // thread such as a AnonymousIoService thread. + failoverThread.setDaemon(false); + failoverThread.start(); + } } public void readerIdle() @@ -293,7 +288,7 @@ public class AMQProtocolHandler implements ProtocolEngine _logger.warn("Timed out while waiting for heartbeat from peer."); _networkDriver.close(); } - + public void writerIdle() { _logger.debug("Protocol Session [" + this + "] idle: reader"); @@ -365,6 +360,7 @@ public class AMQProtocolHandler implements ProtocolEngine public void propagateExceptionToAllWaiters(Exception e) { getStateManager().error(e); + propagateExceptionToFrameListeners(e); } @@ -582,7 +578,7 @@ public class AMQProtocolHandler implements ProtocolEngine } _connection.bytesSent(_writtenBytes); - + if (wait) { _networkDriver.flush(); @@ -642,7 +638,7 @@ public class AMQProtocolHandler implements ProtocolEngine _frameListeners.add(listener); //FIXME: At this point here we should check or before add we should check _stateManager is in an open - // state so as we don't check we are likely just to time out here as I believe is being seen in QPID-1255 + // state so as we don't check we are likely just to time out here as I believe is being seen in QPID-1255 } writeFrame(frame); @@ -828,7 +824,7 @@ public class AMQProtocolHandler implements ProtocolEngine { _networkDriver = driver; } - + /** @param delay delay in seconds (not ms) */ void initHeartbeats(int delay) { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java index cd049c24a1..8910920017 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java @@ -102,7 +102,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession public AMQProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection) { - _protocolHandler = protocolHandler; + _protocolHandler = protocolHandler; _protocolVersion = connection.getProtocolVersion(); _methodDispatcher = ClientMethodDispatcherImpl.newMethodDispatcher(ProtocolVersion.getLatestSupportedVersion(), this); @@ -156,7 +156,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession public SaslClient getSaslClient() { - return _saslClient; + return _saslClient; } /** @@ -192,7 +192,7 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession * @throws AMQException if this was not expected */ public void unprocessedMessageReceived(final int channelId, UnprocessedMessage message) throws AMQException - { + { if ((channelId & FAST_CHANNEL_ACCESS_MASK) == 0) { _channelId2UnprocessedMsgArray[channelId] = message; @@ -468,4 +468,11 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession { // No-op, interface munging } + + + @Override + public String toString() + { + return "AMQProtocolSession[" + _connection + ']'; + } } diff --git a/qpid/java/common/Composite.tpl b/qpid/java/common/Composite.tpl index c46d0a12cc..97b7d01f3c 100644 --- a/qpid/java/common/Composite.tpl +++ b/qpid/java/common/Composite.tpl @@ -127,7 +127,12 @@ if fields: ${ for f in fields: if f.option: continue - out(" $(f.set)($(f.name));\n") + if f.ref_type != f.type: + out(" $(f.set)($(f.name));\n") + else: + out(" if($(f.name) != null) {\n") + out(" $(f.set)($(f.name));\n") + out(" }\n") if segments: out(" setHeader(header);\n") diff --git a/qpid/java/common/genutil.py b/qpid/java/common/genutil.py index 5a75c2e48c..57a461ed40 100644 --- a/qpid/java/common/genutil.py +++ b/qpid/java/common/genutil.py @@ -198,6 +198,7 @@ class Field: self.read = "dec.read%s()" % self.coder self.write = "enc.write%s(check(struct).%s)" % (self.coder, self.name) self.type = jtype(self.type_node) + self.ref_type = jref(self.type) self.default = DEFAULTS.get(self.type, "null") self.has = camel(1, "has", self.name) self.get = camel(1, "get", self.name) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java index 05fd2bb480..374644b4f2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java @@ -50,7 +50,7 @@ public final class AMQDataBlockEncoder implements MessageEncoder { _logger.debug("Encoded frame byte-buffer is '" + EncodingUtils.convertToHexString(buffer) + "'"); } - + out.write(buffer); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java index 1ff39ca790..647d531476 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java @@ -22,6 +22,10 @@ package org.apache.qpid.framing; import org.apache.mina.common.ByteBuffer; +import java.util.Date; +import java.util.Map; +import java.math.BigDecimal; + /** * AMQTypedValue combines together a native Java Object value, and an {@link AMQType}, as a fully typed AMQP parameter * value. It provides the ability to read and write fully typed parameters to and from byte buffers. It also provides @@ -113,4 +117,63 @@ public class AMQTypedValue return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode()); } + + public static AMQTypedValue toTypedValue(Object val) + { + if(val == null) + { + return AMQType.VOID.asTypedValue(null); + } + + Class klass = val.getClass(); + if(klass == String.class) + { + return AMQType.ASCII_STRING.asTypedValue(val); + } + else if(klass == Character.class) + { + return AMQType.ASCII_CHARACTER.asTypedValue(val); + } + else if(klass == Integer.class) + { + return AMQType.INT.asTypedValue(val); + } + else if(klass == Long.class) + { + return AMQType.LONG.asTypedValue(val); + } + else if(klass == Float.class) + { + return AMQType.FLOAT.asTypedValue(val); + } + else if(klass == Double.class) + { + return AMQType.DOUBLE.asTypedValue(val); + } + else if(klass == Date.class) + { + return AMQType.TIMESTAMP.asTypedValue(val); + } + else if(klass == Byte.class) + { + return AMQType.BYTE.asTypedValue(val); + } + else if(klass == Boolean.class) + { + return AMQType.BOOLEAN.asTypedValue(val); + } + else if(klass == byte[].class) + { + return AMQType.BINARY.asTypedValue(val); + } + else if(klass == BigDecimal.class) + { + return AMQType.DECIMAL.asTypedValue(val); + } + else if(val instanceof Map) + { + return AMQType.FIELD_TABLE.asTypedValue(FieldTable.convertToFieldTable((Map)val)); + } + return null; + } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java index ed01c91804..9b2f9b3969 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java @@ -828,6 +828,7 @@ public class FieldTable recalculateEncodedSize(); } + public static interface FieldTableElementProcessor { public boolean processElement(String propertyName, AMQTypedValue value); @@ -904,10 +905,13 @@ public class FieldTable } } + public Object get(String key) + { + return get(new AMQShortString(key)); + } public Object get(AMQShortString key) { - return getObject(key); } @@ -1184,4 +1188,24 @@ public class FieldTable return _properties.equals(f._properties); } + + public static FieldTable convertToFieldTable(Map<String, Object> map) + { + if (map != null) + { + FieldTable table = new FieldTable(); + for(Map.Entry<String,Object> entry : map.entrySet()) + { + table.put(new AMQShortString(entry.getKey()), entry.getValue()); + } + + return table; + } + else + { + return null; + } + } + + } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java index 0a1cedc4e6..7544d9b7e7 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java @@ -23,10 +23,14 @@ package org.apache.qpid.framing.abstraction; import org.apache.qpid.framing.AMQBody; +import java.nio.ByteBuffer; + public interface ProtocolVersionMethodConverter extends MessagePublishInfoConverter { AMQBody convertToBody(ContentChunk contentBody); ContentChunk convertToContentChunk(AMQBody body); void configure(); + + AMQBody convertToBody(ByteBuffer buf); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java index a5c5e5f22d..1c4a29b106 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java @@ -72,6 +72,11 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot } + public AMQBody convertToBody(java.nio.ByteBuffer buf) + { + return new ContentBody(ByteBuffer.wrap(buf)); + } + public MessagePublishInfo convertToInfo(AMQMethodBody methodBody) { final BasicPublishBody publishBody = ((BasicPublishBody) methodBody); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java index 1b0be2b9cc..c87820b9b2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java @@ -80,6 +80,11 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot _basicPublishMethodId = BasicPublishBodyImpl.METHOD_ID; } + + public AMQBody convertToBody(java.nio.ByteBuffer buf) + { + return new ContentBody(ByteBuffer.wrap(buf)); + } public MessagePublishInfo convertToInfo(AMQMethodBody methodBody) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java b/qpid/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java index 5bfc189b02..31953ea6ab 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java @@ -28,38 +28,34 @@ import org.apache.qpid.transport.Receiver; /** * A ProtocolEngine is a Receiver for java.nio.ByteBuffers. It takes the data passed to it in the received - * decodes it and then process the result. - */ -public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer> -{ - // Sets the network driver providing data for this ProtocolEngine + * decodes it and then process the result. + */ +public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer> +{ + // Sets the network driver providing data for this ProtocolEngine void setNetworkDriver (NetworkDriver driver); - - // Returns the remote address of the NetworkDriver + + // Returns the remote address of the NetworkDriver SocketAddress getRemoteAddress(); - // Returns the local address of the NetworkDriver + // Returns the local address of the NetworkDriver SocketAddress getLocalAddress(); - - // Returns number of bytes written + + // Returns number of bytes written long getWrittenBytes(); - - // Returns number of bytes read + + // Returns number of bytes read long getReadBytes(); - - // Called by the NetworkDriver when the socket has been closed for reading + + // Called by the NetworkDriver when the socket has been closed for reading void closed(); - - // Called when the NetworkEngine has not written data for the specified period of time (will trigger a - // heartbeat) + + // Called when the NetworkEngine has not written data for the specified period of time (will trigger a + // heartbeat) void writerIdle(); - - // Called when the NetworkEngine has not read data for the specified period of time (will close the connection) + + // Called when the NetworkEngine has not read data for the specified period of time (will close the connection) void readerIdle(); - - /** - * Accepts an AMQFrame for writing to the network. The ProtocolEngine encodes the frame into bytes and - * passes the data onto the NetworkDriver for sending - */ - void writeFrame(AMQDataBlock frame); -}
\ No newline at end of file + + +}
\ No newline at end of file diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java index 1cdd1da72b..3403b591f3 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java @@ -55,7 +55,7 @@ public class Connection extends ConnectionInvoker private static final Logger log = Logger.get(Connection.class); - enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD } + public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD } class DefaultConnectionListener implements ConnectionListener { @@ -84,7 +84,8 @@ public class Connection extends ConnectionInvoker private SaslServer saslServer; private SaslClient saslClient; private long idleTimeout = 0; - + private String _authorizationID; + // want to make this final private int _connectionId; @@ -118,7 +119,7 @@ public class Connection extends ConnectionInvoker sender.setIdleTimeout(idleTimeout); } - void setState(State state) + protected void setState(State state) { synchronized (lock) { @@ -315,7 +316,14 @@ public class Connection extends ConnectionInvoker public void dispatch(Method method) { Session ssn = getSession(method.getChannel()); - ssn.received(method); + if(ssn != null) + { + ssn.received(method); + } + else + { + // TODO + } } public int getChannelMax() @@ -525,7 +533,17 @@ public class Connection extends ConnectionInvoker { return idleTimeout; } - + + public void setAuthorizationID(String authorizationID) + { + _authorizationID = authorizationID; + } + + public String getAuthorizationID() + { + return _authorizationID; + } + public String toString() { return String.format("conn:%x", System.identityHashCode(this)); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Method.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Method.java index 611c742fb1..3c80180d0b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Method.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Method.java @@ -35,6 +35,7 @@ import static org.apache.qpid.transport.util.Functions.*; public abstract class Method extends Struct implements ProtocolEvent { + public static final Method create(int type) { // XXX: should generate separate factories for separate @@ -43,12 +44,18 @@ public abstract class Method extends Struct implements ProtocolEvent } // XXX: command subclass? + public static interface CompletionListener + { + public void onComplete(Method method); + } + private int id; private int channel; private boolean idSet = false; private boolean sync = false; private boolean batch = false; private boolean unreliable = false; + private CompletionListener completionListener; public final int getId() { @@ -61,6 +68,11 @@ public abstract class Method extends Struct implements ProtocolEvent this.idSet = true; } + boolean idSet() + { + return idSet; + } + public final int getChannel() { return channel; @@ -76,7 +88,7 @@ public abstract class Method extends Struct implements ProtocolEvent return sync; } - final void setSync(boolean value) + public final void setSync(boolean value) { this.sync = value; } @@ -152,6 +164,26 @@ public abstract class Method extends Struct implements ProtocolEvent } } + + public void setCompletionListener(CompletionListener completionListener) + { + this.completionListener = completionListener; + } + + public void complete() + { + if(completionListener!= null) + { + completionListener.onComplete(this); + completionListener = null; + } + } + + public boolean hasCompletionListener() + { + return completionListener != null; + } + public String toString() { StringBuilder str = new StringBuilder(); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java index 9b2744ee8b..3850dc162b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java @@ -52,6 +52,11 @@ public final class RangeSet implements Iterable<Range> return ranges.getFirst(); } + public Range getLast() + { + return ranges.getLast(); + } + public boolean includes(Range range) { for (Range r : this) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java index 2833565afc..453921ea2b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java @@ -52,13 +52,28 @@ public class ServerDelegate extends ConnectionDelegate { private SaslServer saslServer; + private List<Object> _locales; + private List<Object> _mechanisms; + private Map<String, Object> _clientProperties; + + + public ServerDelegate() + { + this(null, Collections.EMPTY_LIST, Collections.singletonList((Object)"utf8")); + } + + protected ServerDelegate(Map<String, Object> clientProperties, List<Object> mechanisms, List<Object> locales) + { + _clientProperties = clientProperties; + _mechanisms = mechanisms; + _locales = locales; + } public void init(Connection conn, ProtocolHeader hdr) { conn.send(new ProtocolHeader(1, 0, 10)); - List<Object> utf8 = new ArrayList<Object>(); - utf8.add("utf8"); - conn.connectionStart(null, Collections.EMPTY_LIST, utf8); + + conn.connectionStart(_clientProperties, _mechanisms, _locales); } @Override public void connectionStartOk(Connection conn, ConnectionStartOk ok) @@ -77,8 +92,8 @@ public class ServerDelegate extends ConnectionDelegate try { - SaslServer ss = Sasl.createSaslServer - (mechanism, "AMQP", "localhost", null, null); + + SaslServer ss = createSaslServer(mechanism); if (ss == null) { conn.connectionClose @@ -95,6 +110,14 @@ public class ServerDelegate extends ConnectionDelegate } } + protected SaslServer createSaslServer(String mechanism) + throws SaslException + { + SaslServer ss = Sasl.createSaslServer + (mechanism, "AMQP", "localhost", null, null); + return ss; + } + private void secure(Connection conn, byte[] response) { SaslServer ss = conn.getSaslServer(); @@ -108,6 +131,7 @@ public class ServerDelegate extends ConnectionDelegate (Integer.MAX_VALUE, org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE, 0, Integer.MAX_VALUE); + conn.setAuthorizationID(ss.getAuthorizationID()); } else { @@ -133,9 +157,16 @@ public class ServerDelegate extends ConnectionDelegate @Override public void connectionOpen(Connection conn, ConnectionOpen open) { conn.connectionOpenOk(Collections.EMPTY_LIST); + conn.setState(OPEN); } + protected Session getSession(Connection conn, SessionDelegate delegate, SessionAttach atc) + { + return new Session(conn, delegate, new Binary(atc.getName()), 0); + } + + public Session getSession(Connection conn, SessionAttach atc) { return new Session(conn, new Binary(atc.getName()), 0); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java index 3dca4fc44e..818bb19c08 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java @@ -81,7 +81,7 @@ public class Session extends SessionInvoker private Binary name; private long expiry; private int channel; - private SessionDelegate delegate = new SessionDelegate(); + private SessionDelegate delegate; private SessionListener listener = new DefaultSessionListener(); private long timeout = 60000; private boolean autoSync = false; @@ -111,9 +111,15 @@ public class Session extends SessionInvoker private Thread resumer = null; - Session(Connection connection, Binary name, long expiry) + protected Session(Connection connection, Binary name, long expiry) + { + this(connection, new SessionDelegate(), name, expiry); + } + + protected Session(Connection connection, SessionDelegate delegate, Binary name, long expiry) { this.connection = connection; + this.delegate = delegate; this.name = name; this.expiry = expiry; initReceiver(); @@ -440,7 +446,7 @@ public class Session extends SessionInvoker } } - boolean complete(int lower, int upper) + protected boolean complete(int lower, int upper) { //avoid autoboxing if(log.isDebugEnabled()) @@ -457,8 +463,9 @@ public class Session extends SessionInvoker if (m != null) { commandBytes -= m.getBodySize(); + m.complete(); + commands[idx] = null; } - commands[idx] = null; } if (le(lower, maxComplete + 1)) { @@ -486,13 +493,28 @@ public class Session extends SessionInvoker } } - final private boolean isFull(int id) + protected boolean isFull(int id) + { + return isCommandsFull(id) || isBytesFull(); + } + + protected boolean isBytesFull() { - return id - maxComplete >= commands.length || commandBytes >= byteLimit; + return commandBytes >= byteLimit; + } + + protected boolean isCommandsFull(int id) + { + return id - maxComplete >= commands.length; } public void invoke(Method m) { + invoke(m,(Runnable)null); + } + + public void invoke(Method m, Runnable postIdSettingAction) + { if (m.getEncodedTrack() == Frame.L4) { if (m.hasPayload()) @@ -553,8 +575,13 @@ public class Session extends SessionInvoker "(state=%s)", state)); } - int next = commandsOut++; + int next; + next = commandsOut++; m.setId(next); + if(postIdSettingAction != null) + { + postIdSettingAction.run(); + } if (isFull(next)) { @@ -607,7 +634,7 @@ public class Session extends SessionInvoker { sessionCommandPoint(0, 0); } - if (expiry > 0 && !m.isUnreliable()) + if ((expiry > 0 && !m.isUnreliable()) || m.hasCompletionListener()) { commands[mod(next, commands.length)] = m; commandBytes += m.getBodySize(); @@ -617,6 +644,7 @@ public class Session extends SessionInvoker m.setSync(true); } needSync = !m.isSync(); + try { send(m); @@ -641,7 +669,7 @@ public class Session extends SessionInvoker // flush every 64K commands to avoid ambiguity on // wraparound - if ((next % 65536) == 0) + if (shouldIssueFlush(next)) { try { @@ -669,6 +697,11 @@ public class Session extends SessionInvoker } } + protected boolean shouldIssueFlush(int next) + { + return (next % 65536) == 0; + } + public void sync() { sync(timeout); @@ -910,6 +943,14 @@ public class Session extends SessionInvoker } } } + if(state == CLOSED) + { + delegate.closed(this); + } + else + { + delegate.detached(this); + } } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java index c8d0855607..6146f029b2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java @@ -184,4 +184,11 @@ public class SessionDelegate } } + public void closed(Session session) + { + } + + public void detached(Session session) + { + } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java index 33d552b91e..357caa26e1 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java @@ -186,8 +186,9 @@ public class Assembler implements Receiver<NetworkEvent>, NetworkDelegate case COMMAND: int commandType = dec.readUint16(); // read in the session header, right now we don't use it - dec.readUint16(); + int hdr = dec.readUint16(); command = Method.create(commandType); + command.setSync((0x0001 & hdr) != 0); command.read(dec); if (command.hasPayload()) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java index 408c95e075..2132fc2c03 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java @@ -39,7 +39,7 @@ import static org.apache.qpid.transport.network.InputHandler.State.*; * @author Rafael H. Schloming */ -public final class InputHandler implements Receiver<ByteBuffer> +public class InputHandler implements Receiver<ByteBuffer> { public enum State diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java index 6144edb947..ea48e48721 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java @@ -137,6 +137,7 @@ final class IoReceiver implements Runnable } catch (Throwable t) { + t.printStackTrace(); if (!(shutdownBroken && t instanceof SocketException && t.getMessage().equalsIgnoreCase("socket closed") && diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java index b0d1c46572..3838bf76be 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java @@ -229,7 +229,7 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver if (_socketConnector instanceof SocketConnector) { ((SocketConnector) _socketConnector).setWorkerTimeout(0); - } + } ConnectFuture future = _socketConnector.connect(new InetSocketAddress(destination, port), this, cfg); future.join(); @@ -279,7 +279,10 @@ public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver public void send(ByteBuffer msg) { - _lastWriteFuture = _ioSession.write(org.apache.mina.common.ByteBuffer.wrap(msg)); + org.apache.mina.common.ByteBuffer minaBuf = org.apache.mina.common.ByteBuffer.allocate(msg.capacity()); + minaBuf.put(msg); + minaBuf.flip(); + _lastWriteFuture = _ioSession.write(minaBuf); } public void setIdleTimeout(long l) diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java index 784943b404..b2fdf48267 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java @@ -113,12 +113,12 @@ public class MessageListenerMultiConsumerTest extends QpidTestCase for (int loops = 0; (msg < MSG_COUNT) || (loops < MAX_LOOPS); loops++) { - if (_consumer1.receive(100) != null) + if (_consumer1.receive(1000) != null) { msg++; } - if (_consumer2.receive(100) != null) + if (_consumer2.receive(1000) != null) { msg++; } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java index ba05dc6b3e..266cb42ad7 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java @@ -215,7 +215,7 @@ public class BindingLoggingTest extends AbstractTestLogging List<String> results = _monitor.findMatches(BND_PREFIX); // We will have two binds as we bind all queues to the default exchange - assertEquals("Result set larger than expected.", 4, results.size()); + assertEquals("Result not as expected." + results, 4, results.size()); String messageID = "BND-1001"; @@ -241,7 +241,7 @@ public class BindingLoggingTest extends AbstractTestLogging String subject = fromSubject(log); - assertTrue("Routing Key does not start with TempQueue:"+AbstractTestLogSubject.getSlice("rk", subject), + assertTrue("Routing Key does not start with TempQueue:"+AbstractTestLogSubject.getSlice("rk", subject), AbstractTestLogSubject.getSlice("rk", subject).startsWith("TempQueue")); assertEquals("Virtualhost not correct.", "/test", AbstractTestLogSubject.getSlice("vh", subject)); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java index 509c027cbf..fe25bf07f0 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SubscriptionTestHelper.java @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,6 +34,7 @@ public class SubscriptionTestHelper implements Subscription private final List<QueueEntry> messages; private final Object key; private boolean isSuspended; + private AMQQueue.Context _queueContext; public SubscriptionTestHelper(Object key) { @@ -59,6 +60,11 @@ public class SubscriptionTestHelper implements Subscription public void setQueue(AMQQueue queue, boolean exclusive) { + + } + + public void setNoLocal(boolean noLocal) + { } @@ -102,24 +108,34 @@ public class SubscriptionTestHelper implements Subscription //To change body of implemented methods use File | Settings | File Templates. } - public void restoreCredit(final QueueEntry queueEntry) + public void onDequeue(final QueueEntry queueEntry) { } + public void restoreCredit(QueueEntry queueEntry) + { + //To change body of implemented methods use File | Settings | File Templates. + } + public void setStateListener(final StateListener listener) { //To change body of implemented methods use File | Settings | File Templates. } - + public State getState() { return null; //To change body of implemented methods use File | Settings | File Templates. } - public QueueEntry getLastSeenEntry() + public AMQQueue.Context getQueueContext() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return _queueContext; + } + + public void setQueueContext(AMQQueue.Context queueContext) + { + _queueContext = queueContext; } public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue) @@ -131,7 +147,7 @@ public class SubscriptionTestHelper implements Subscription { return null; } - + public void start() { //no-op @@ -152,6 +168,21 @@ public class SubscriptionTestHelper implements Subscription return false; //To change body of implemented methods use File | Settings | File Templates. } + public void confirmAutoClose() + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void set(String key, Object value) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public Object get(String key) + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public LogActor getLogActor() { return null; //To change body of implemented methods use File | Settings | File Templates. @@ -167,6 +198,11 @@ public class SubscriptionTestHelper implements Subscription return null; //To change body of implemented methods use File | Settings | File Templates. } + public QueueEntry.SubscriptionAssignedState getAssignedState() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public void queueDeleted(AMQQueue queue) { } @@ -216,6 +252,16 @@ public class SubscriptionTestHelper implements Subscription return false; } + public boolean acquires() + { + return true; + } + + public boolean seesRequeues() + { + return true; + } + public boolean isBrowser() { return false; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java index dde235f73e..9487f72ac8 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java @@ -873,7 +873,12 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener { Throwable cause = e.getLinkedException(); - if (!(cause instanceof AMQAuthenticationException)) + if (cause == null) + { + e.printStackTrace(System.out); + fail("JMS Exception did not have cause"); + } + else if (!(cause instanceof AMQAuthenticationException)) { cause.printStackTrace(System.out); assertEquals("Incorrect exception", IllegalStateException.class, cause.getClass()); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java index 7d8c81f4d5..b41aa661ea 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java @@ -25,15 +25,14 @@ import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.MessageMetaData; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.logging.LogSubject; import java.util.HashMap; import java.util.Iterator; +import java.nio.ByteBuffer; public class SlowMessageStore implements MessageStore { @@ -47,14 +46,21 @@ public class SlowMessageStore implements MessageStore private static final String POST = "post"; private String DEFAULT_DELAY = "default"; - public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception + // ***** MessageStore Interface. + + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception { - _logger.info("Starting SlowMessageStore on Virtualhost:" + virtualHost.getName()); - Configuration delays = config.getStoreConfiguration().subset(DELAYS); + //To change body of implemented methods use File | Settings | File Templates. + + _logger.info("Starting SlowMessageStore on Virtualhost:" + name); + Configuration delays = config.subset(DELAYS); configureDelays(delays); - String messageStoreClass = config.getStoreConfiguration().getString("realStore"); + String messageStoreClass = config.getString("realStore"); if (delays.containsKey(DEFAULT_DELAY)) { @@ -73,11 +79,11 @@ public class SlowMessageStore implements MessageStore " does not."); } _realStore = (MessageStore) o; - _realStore.configure(virtualHost, base + ".store", config); + _realStore.configureConfigStore(name, recoveryHandler, config, logSubject); } else { - _realStore.configure(virtualHost, base + ".store", config); + _realStore.configureConfigStore(name, recoveryHandler, config, logSubject); } } @@ -133,7 +139,7 @@ public class SlowMessageStore implements MessageStore } long slept = (System.nanoTime() - start) / 1000000; - + if (slept >= delay) { _logger.info("Done sleep for:" + slept+":"+delay); @@ -146,7 +152,14 @@ public class SlowMessageStore implements MessageStore } } - // ***** MessageStore Interface. + + public void configureMessageStore(String name, + MessageStoreRecoveryHandler recoveryHandler, + Configuration config, + LogSubject logSubject) throws Exception + { + _realStore.configureMessageStore(name, recoveryHandler, config, logSubject); + } public void close() throws Exception { @@ -155,13 +168,12 @@ public class SlowMessageStore implements MessageStore doPostDelay("close"); } - public void removeMessage(StoreContext storeContext, Long messageId) throws AMQException + public <M extends StorableMessageMetaData> StoredMessage<M> addMessage(M metaData) { - doPreDelay("removeMessage"); - _realStore.removeMessage(storeContext, messageId); - doPostDelay("removeMessage"); + return _realStore.addMessage(metaData); } + public void createExchange(Exchange exchange) throws AMQException { doPreDelay("createExchange"); @@ -209,90 +221,93 @@ public class SlowMessageStore implements MessageStore doPostDelay("removeQueue"); } - public void enqueueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException - { - doPreDelay("enqueueMessage"); - _realStore.enqueueMessage(context, queue, messageId); - doPostDelay("enqueueMessage"); - } - - public void dequeueMessage(StoreContext context, AMQQueue queue, Long messageId) throws AMQException + public void configureTransactionLog(String name, + TransactionLogRecoveryHandler recoveryHandler, + Configuration storeConfiguration, LogSubject logSubject) + throws Exception { - doPreDelay("dequeueMessage"); - _realStore.dequeueMessage(context, queue, messageId); - doPostDelay("dequeueMessage"); + _realStore.configureTransactionLog(name, recoveryHandler, storeConfiguration, logSubject); } - public void beginTran(StoreContext context) throws AMQException + public Transaction newTransaction() { doPreDelay("beginTran"); - _realStore.beginTran(context); + Transaction txn = new SlowTransaction(_realStore.newTransaction()); doPostDelay("beginTran"); + return txn; } - public void commitTran(StoreContext context) throws AMQException - { - doPreDelay("commitTran"); - _realStore.commitTran(context); - doPostDelay("commitTran"); - } - public void abortTran(StoreContext context) throws AMQException + public boolean isPersistent() { - doPreDelay("abortTran"); - _realStore.abortTran(context); - doPostDelay("abortTran"); + return _realStore.isPersistent(); } - public boolean inTran(StoreContext context) + public void storeMessageHeader(Long messageNumber, ServerMessage message) { - doPreDelay("inTran"); - boolean b = _realStore.inTran(context); - doPostDelay("inTran"); - return b; + //To change body of implemented methods use File | Settings | File Templates. } - public Long getNewMessageId() + public void storeContent(Long messageNumber, long offset, ByteBuffer body) { - doPreDelay("getNewMessageId"); - Long l = _realStore.getNewMessageId(); - doPostDelay("getNewMessageId"); - return l; + //To change body of implemented methods use File | Settings | File Templates. } - public void storeContentBodyChunk(StoreContext context, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException + public ServerMessage getMessage(Long messageNumber) { - doPreDelay("storeContentBodyChunk"); - _realStore.storeContentBodyChunk(context, messageId, index, contentBody, lastContentBody); - doPostDelay("storeContentBodyChunk"); + return null; //To change body of implemented methods use File | Settings | File Templates. } - public void storeMessageMetaData(StoreContext context, Long messageId, MessageMetaData messageMetaData) throws AMQException + private class SlowTransaction implements Transaction { - doPreDelay("storeMessageMetaData"); - _realStore.storeMessageMetaData(context, messageId, messageMetaData); - doPostDelay("storeMessageMetaData"); - } + private final Transaction _underlying; - public MessageMetaData getMessageMetaData(StoreContext context, Long messageId) throws AMQException - { - doPreDelay("getMessageMetaData"); - MessageMetaData mmd = _realStore.getMessageMetaData(context, messageId); - doPostDelay("getMessageMetaData"); - return mmd; - } + private SlowTransaction(Transaction underlying) + { + _underlying = underlying; + } - public ContentChunk getContentBodyChunk(StoreContext context, Long messageId, int index) throws AMQException - { - doPreDelay("getContentBodyChunk"); - ContentChunk c = _realStore.getContentBodyChunk(context, messageId, index); - doPostDelay("getContentBodyChunk"); - return c; - } + public void enqueueMessage(TransactionLogResource queue, Long messageId) + throws AMQException + { + doPreDelay("enqueueMessage"); + _underlying.enqueueMessage(queue, messageId); + doPostDelay("enqueueMessage"); + } - public boolean isPersistent() - { - return _realStore.isPersistent(); + public void dequeueMessage(TransactionLogResource queue, Long messageId) + throws AMQException + { + doPreDelay("dequeueMessage"); + _underlying.dequeueMessage(queue, messageId); + doPostDelay("dequeueMessage"); + } + + public void commitTran() + throws AMQException + { + doPreDelay("commitTran"); + _underlying.commitTran(); + doPostDelay("commitTran"); + } + + public StoreFuture commitTranAsync() + throws AMQException + { + doPreDelay("commitTran"); + StoreFuture future = _underlying.commitTranAsync(); + doPostDelay("commitTran"); + return future; + } + + public void abortTran() + throws AMQException + { + doPreDelay("abortTran"); + _underlying.abortTran(); + doPostDelay("abortTran"); + } } + } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java index 25b9b0ba14..5ea203bda3 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java @@ -81,9 +81,14 @@ public class CancelTest extends QpidTestCase assertTrue(e.hasMoreElements()); + int i = 0; while (e.hasMoreElements()) { e.nextElement(); + if(++i > 1) + { + fail("Two many elemnts to browse!"); + } } browser.close(); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java index d1bcaa1bb8..eb0c539a6e 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java @@ -79,7 +79,7 @@ public class DupsOkTest extends QpidTestCase * This test sends x messages and receives them with an async consumer. * Waits for all messages to be received or for 60 s * and checks whether the queue is empty. - * + * * @throws Exception */ public void testDupsOK() throws Exception @@ -93,7 +93,7 @@ public class DupsOkTest extends QpidTestCase assertEquals("The queue should have msgs at start", MSG_COUNT, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue)); - clientConnection.start(); + clientConnection.start(); consumer.setMessageListener(new MessageListener() { @@ -110,7 +110,7 @@ public class DupsOkTest extends QpidTestCase if (message instanceof TextMessage) { try - { + { if (message.getIntProperty("count") == MSG_COUNT) { try @@ -156,7 +156,11 @@ public class DupsOkTest extends QpidTestCase // before the dispatcher has sent the ack back to the broker. consumer.close(); - assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue)); + clientSession.close(); + + final Session clientSession2 = clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + + assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession2).getQueueDepth((AMQDestination) _queue)); clientConnection.close(); } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java index e9aed4de01..9558f23b89 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java @@ -79,16 +79,22 @@ public class LargeMessageTest extends QpidTestCase } // Test boundary of 1 packet to 2 packets - public void test64kminus1() + public void test64kminus9() { - checkLargeMessage((64 * 1024) - 1); + checkLargeMessage((64 * 1024) - 9); } - public void test64k() + public void test64kminus8() { - checkLargeMessage(64 * 1024); + checkLargeMessage((64 * 1024)-8); } + public void test64kminus7() + { + checkLargeMessage((64 * 1024)-7); + } + + public void test64kplus1() { checkLargeMessage((64 * 1024) + 1); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java index ec23256f38..f1cac22f08 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java @@ -50,7 +50,8 @@ public class MessageRequeueTest extends QpidTestCase protected final String queue = "direct://amq.direct//message-requeue-test-queue"; protected String payload = "Message:"; - protected final String BROKER = "vm://:1"; + //protected final String BROKER = "vm://:1"; + protected final String BROKER = "tcp://127.0.0.1:5672"; private boolean testReception = true; private long[] receieved = new long[numTestMessages + 1]; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java index f8ba7060a9..742e2ac518 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java @@ -311,11 +311,13 @@ public class TopicSessionTest extends QpidTestCase AMQTopic topic = new AMQTopic(con, "testNoLocal"); - TopicSession session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); + TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); TopicSubscriber noLocal = session1.createSubscriber(topic, "", true); + TopicSubscriber select = session1.createSubscriber(topic, "Selector = 'select'", false); TopicSubscriber normal = session1.createSubscriber(topic); + TopicPublisher publisher = session1.createPublisher(topic); con.start(); @@ -329,12 +331,12 @@ public class TopicSessionTest extends QpidTestCase m = (TextMessage) normal.receive(1000); assertNotNull(m); session1.commit(); - + //test selector subscriber doesn't message m = (TextMessage) select.receive(1000); assertNull(m); session1.commit(); - + //test nolocal subscriber doesn't message m = (TextMessage) noLocal.receive(1000); if (m != null) @@ -349,12 +351,12 @@ public class TopicSessionTest extends QpidTestCase publisher.publish(message); session1.commit(); - + //test normal subscriber gets message m = (TextMessage) normal.receive(1000); assertNotNull(m); session1.commit(); - + //test selector subscriber does get message m = (TextMessage) select.receive(1000); assertNotNull(m); @@ -365,7 +367,7 @@ public class TopicSessionTest extends QpidTestCase assertNull(m); AMQConnection con2 = (AMQConnection) getConnection("guest", "guest", "foo"); - TopicSession session2 = con2.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); + TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); TopicPublisher publisher2 = session2.createPublisher(topic); @@ -386,18 +388,18 @@ public class TopicSessionTest extends QpidTestCase session1.commit(); //test nolocal subscriber does message - m = (TextMessage) noLocal.receive(100); + m = (TextMessage) noLocal.receive(1000); assertNotNull(m); con.close(); con2.close(); } - + /** * This tests QPID-1191, where messages which are sent to a topic but are not consumed by a subscriber * due to a selector can be leaked. - * @throws Exception + * @throws Exception */ public void testNonMatchingMessagesDoNotFillQueue() throws Exception { @@ -420,27 +422,27 @@ public class TopicSessionTest extends QpidTestCase message = session.createTextMessage("non-matching 1"); publisher.publish(message); session.commit(); - + // Send and consume matching message message = session.createTextMessage("hello"); message.setStringProperty("Selector", "select"); publisher.publish(message); session.commit(); - + m = (TextMessage) selector.receive(1000); assertNotNull("should have received message", m); assertEquals("Message contents were wrong", "hello", m.getText()); - + // Send non-matching message message = session.createTextMessage("non-matching 2"); publisher.publish(message); session.commit(); - + // Assert queue count is 0 long depth = ((AMQTopicSessionAdaptor) session).getSession().getQueueDepth(topic); assertEquals("Queue depth was wrong", 0, depth); - + } public static junit.framework.Test suite() diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java index 0426c4f45f..b1d14721bd 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java @@ -23,6 +23,8 @@ package org.apache.qpid.test.utils; import org.apache.qpid.util.FileUtils; import javax.naming.NamingException; +import javax.jms.JMSException; +import javax.naming.NamingException; import org.apache.qpid.client.AMQConnectionFactory; import org.slf4j.Logger; diff --git a/qpid/java/test-profiles/java-derby.testprofile b/qpid/java/test-profiles/java-derby.testprofile index e7c1dc1fd6..2887501a9b 100644 --- a/qpid/java/test-profiles/java-derby.testprofile +++ b/qpid/java/test-profiles/java-derby.testprofile @@ -1,8 +1,8 @@ broker.language=java -broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml +broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT --exclude-0-10 @PORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB broker.ready=BRK-1004 broker.stopped=Exception broker.config=${project.root}/build/etc/config-systests-derby.xml - +qpid.amqp.version=0-9 profile.excludes=08StandaloneExcludes diff --git a/qpid/java/test-profiles/java.0.10.testprofile b/qpid/java/test-profiles/java.0.10.testprofile new file mode 100755 index 0000000000..35e3530cab --- /dev/null +++ b/qpid/java/test-profiles/java.0.10.testprofile @@ -0,0 +1,8 @@ +broker.language=java +broker.version=0-10 +broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml +broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB +broker.ready=BRK-1004 +broker.stopped=Exception + +profile.excludes=08TransientExcludes 08StandaloneExcludes 010Excludes 010TransientExcludes diff --git a/qpid/java/test-profiles/java.testprofile b/qpid/java/test-profiles/java.testprofile index 05a801ee06..8dd835a335 100644 --- a/qpid/java/test-profiles/java.testprofile +++ b/qpid/java/test-profiles/java.testprofile @@ -1,7 +1,7 @@ broker.language=java -broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml +broker=${project.root}/build/bin/qpid-server -p @PORT -m @MPORT --exclude-0-10 @PORT -c @CONFIG_FILE -l ${test.profiles}/log4j-test.xml broker.clean=${test.profiles}/clean-dir ${build.data} ${project.root}/build/work/derbyDB broker.ready=BRK-1004 broker.stopped=Exception - +qpid.amqp.version=0-9 profile.excludes=08TransientExcludes 08StandaloneExcludes |