diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2012-03-01 15:42:44 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2012-03-01 15:42:44 +0000 |
commit | e78f6a9e59098ac104892a79b74c9895272b292e (patch) | |
tree | 56d1765b5470746a864b7ab9f26460e477f48e8f | |
parent | 252f863d8ffc90d958daec6040a886f9ff44861c (diff) | |
download | qpid-python-e78f6a9e59098ac104892a79b74c9895272b292e.tar.gz |
NO-JIRA: [AMQP 1-0 Sandbox] merging from trunk
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rg-amqp-1-0-sandbox@1295627 13f79535-47bb-0310-9956-ffa450edef68
236 files changed, 8861 insertions, 6582 deletions
diff --git a/qpid/java/bdbstore/build.xml b/qpid/java/bdbstore/build.xml index 9513e7cc5b..af7c108aa9 100644 --- a/qpid/java/bdbstore/build.xml +++ b/qpid/java/bdbstore/build.xml @@ -24,7 +24,7 @@ <import file="../module.xml" /> <property name="bdb.lib.dir" value="${project.root}/lib/bdbstore" /> - <property name="bdb.version" value="4.0.117" /> + <property name="bdb.version" value="5.0.34" /> <property name="bdb.download.url" value="http://download.oracle.com/maven/com/sleepycat/je/${bdb.version}/je-${bdb.version}.jar" /> <property name="bdb.jar.file" value="${bdb.lib.dir}/je-${bdb.version}.jar" /> diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java index f900159808..2e2d2f0b11 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java @@ -22,27 +22,37 @@ package org.apache.qpid.server.store.berkeleydb; import java.io.File; import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Queue; +import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import com.sleepycat.bind.tuple.LongBinding; +import com.sleepycat.bind.tuple.StringBinding; +import com.sleepycat.je.*; import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.federation.Bridge; +import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; @@ -70,17 +80,6 @@ import org.apache.qpid.server.store.berkeleydb.tuples.QueueTupleBindingFactory; import com.sleepycat.bind.EntryBinding; import com.sleepycat.bind.tuple.ByteBinding; import com.sleepycat.bind.tuple.TupleBinding; -import com.sleepycat.je.CheckpointConfig; -import com.sleepycat.je.Cursor; -import com.sleepycat.je.Database; -import com.sleepycat.je.DatabaseConfig; -import com.sleepycat.je.DatabaseEntry; -import com.sleepycat.je.DatabaseException; -import com.sleepycat.je.Environment; -import com.sleepycat.je.EnvironmentConfig; -import com.sleepycat.je.LockMode; -import com.sleepycat.je.OperationStatus; -import com.sleepycat.je.TransactionConfig; /** * BDBMessageStore implements a persistent {@link MessageStore} using the BDB high performance log. @@ -91,7 +90,7 @@ import com.sleepycat.je.TransactionConfig; * dequeue messages to queues. <tr><td> Generate message identifiers. </table> */ @SuppressWarnings({"unchecked"}) -public class BDBMessageStore implements MessageStore +public class BDBMessageStore implements MessageStore, DurableConfigurationStore { private static final Logger _log = Logger.getLogger(BDBMessageStore.class); @@ -107,19 +106,24 @@ public class BDBMessageStore implements MessageStore private String DELIVERYDB_NAME = "deliveryDb"; private String EXCHANGEDB_NAME = "exchangeDb"; private String QUEUEDB_NAME = "queueDb"; + private String BRIDGEDB_NAME = "bridges"; + private String LINKDB_NAME = "links"; + private Database _messageMetaDataDb; private Database _messageContentDb; private Database _queueBindingsDb; private Database _deliveryDb; private Database _exchangeDb; private Database _queueDb; + private Database _bridgeDb; + private Database _linkDb; /* ======= * Schema: * ======= - * + * * Queue: - * name(AMQShortString) - name(AMQShortString), owner(AMQShortString), + * name(AMQShortString) - name(AMQShortString), owner(AMQShortString), * arguments(FieldTable encoded as binary), exclusive (boolean) * * Exchange: @@ -171,7 +175,7 @@ public class BDBMessageStore implements MessageStore private boolean _configured; - + public BDBMessageStore() { this(DATABASE_FORMAT_VERSION); @@ -197,27 +201,28 @@ public class BDBMessageStore implements MessageStore EXCHANGEDB_NAME += "_v" + version; QUEUEBINDINGSDB_NAME += "_v" + version; + + LINKDB_NAME += "_v" + version; + + BRIDGEDB_NAME += "_v" + version; } } - - public void configureConfigStore(String name, - ConfigurationRecoveryHandler recoveryHandler, + + public void configureConfigStore(String name, + ConfigurationRecoveryHandler recoveryHandler, Configuration storeConfiguration, LogSubject logSubject) throws Exception { - _logSubject = logSubject; - CurrentActor.get().message(_logSubject, ConfigStoreMessages.CREATED(this.getClass().getName())); + CurrentActor.get().message(logSubject, ConfigStoreMessages.CREATED(this.getClass().getName())); - if(_configured) + if(!_configured) { - throw new Exception("ConfigStore already configured"); + _logSubject = logSubject; + configure(name,storeConfiguration); + _configured = true; + stateTransition(State.CONFIGURING, State.CONFIGURED); } - configure(name,storeConfiguration); - - _configured = true; - stateTransition(State.CONFIGURING, State.CONFIGURED); - recover(recoveryHandler); stateTransition(State.RECOVERING, State.STARTED); } @@ -227,11 +232,14 @@ public class BDBMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { - CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); + CurrentActor.get().message(logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); if(!_configured) { - throw new Exception("ConfigStore not configured"); + _logSubject = logSubject; + configure(name,storeConfiguration); + _configured = true; + stateTransition(State.CONFIGURING, State.CONFIGURED); } recoverMessages(recoveryHandler); @@ -240,24 +248,28 @@ public class BDBMessageStore implements MessageStore public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler, Configuration storeConfiguration, LogSubject logSubject) throws Exception { - CurrentActor.get().message(_logSubject, TransactionLogMessages.CREATED(this.getClass().getName())); + CurrentActor.get().message(logSubject, TransactionLogMessages.CREATED(this.getClass().getName())); + if(!_configured) { - throw new Exception("ConfigStore not configured"); + _logSubject = logSubject; + configure(name,storeConfiguration); + _configured = true; + stateTransition(State.CONFIGURING, State.CONFIGURED); } recoverQueueEntries(recoveryHandler); - + } - public org.apache.qpid.server.store.TransactionLog.Transaction newTransaction() + public org.apache.qpid.server.store.MessageStore.Transaction newTransaction() { return new BDBTransaction(); } - + /** * Called after instantiation in order to configure the message store. * @@ -268,8 +280,8 @@ public class BDBMessageStore implements MessageStore */ public boolean configure(String name, Configuration storeConfig) throws Exception { - File environmentPath = new File(storeConfig.getString(ENVIRONMENT_PATH_PROPERTY, - System.getProperty("QPID_WORK") + "/bdbstore/" + name)); + File environmentPath = new File(storeConfig.getString(ENVIRONMENT_PATH_PROPERTY, + System.getProperty("QPID_WORK") + "/bdbstore/" + name)); if (!environmentPath.exists()) { if (!environmentPath.mkdirs()) @@ -288,7 +300,7 @@ public class BDBMessageStore implements MessageStore /** * @param environmentPath location for the store to be created in/recovered from - * @param readonly if true then don't allow modifications to an existing store, and don't create a new store if none exists + * @param readonly if true then don't allow modifications to an existing store, and don't create a new store if none exists * @return whether or not a new store environment was created * @throws AMQStoreException * @throws DatabaseException @@ -301,12 +313,12 @@ public class BDBMessageStore implements MessageStore _log.info("Configuring BDB message store"); createTupleBindingFactories(_version); - + setDatabaseNames(_version); return setupStore(environmentPath, readonly); } - + private void createTupleBindingFactories(int version) { _bindingTupleBindingFactory = new BindingTupleBindingFactory(version); @@ -406,7 +418,7 @@ public class BDBMessageStore implements MessageStore envConfig.setTransactional(true); envConfig.setConfigParam("je.lock.nLockTables", "7"); - // Restore 500,000 default timeout. + // Restore 500,000 default timeout. //envConfig.setLockTimeout(15000); // Added to help diagnosis of Deadlock issue @@ -416,10 +428,10 @@ public class BDBMessageStore implements MessageStore envConfig.setConfigParam("je.txn.deadlockStackTrace", "true"); envConfig.setConfigParam("je.txn.dumpLocks", "true"); } - + // Set transaction mode _transactionConfig.setReadCommitted(true); - + //This prevents background threads running which will potentially update the store. envConfig.setReadOnly(readonly); try @@ -458,15 +470,26 @@ public class BDBMessageStore implements MessageStore //This is required if we are wanting read only access. dbConfig.setReadOnly(readonly); - _messageMetaDataDb = _environment.openDatabase(null, MESSAGEMETADATADB_NAME, dbConfig); - _queueDb = _environment.openDatabase(null, QUEUEDB_NAME, dbConfig); - _exchangeDb = _environment.openDatabase(null, EXCHANGEDB_NAME, dbConfig); - _queueBindingsDb = _environment.openDatabase(null, QUEUEBINDINGSDB_NAME, dbConfig); - _messageContentDb = _environment.openDatabase(null, MESSAGECONTENTDB_NAME, dbConfig); - _deliveryDb = _environment.openDatabase(null, DELIVERYDB_NAME, dbConfig); + _messageMetaDataDb = openDatabase(MESSAGEMETADATADB_NAME, dbConfig); + _queueDb = openDatabase(QUEUEDB_NAME, dbConfig); + _exchangeDb = openDatabase(EXCHANGEDB_NAME, dbConfig); + _queueBindingsDb = openDatabase(QUEUEBINDINGSDB_NAME, dbConfig); + _messageContentDb = openDatabase(MESSAGECONTENTDB_NAME, dbConfig); + _deliveryDb = openDatabase(DELIVERYDB_NAME, dbConfig); + _linkDb = openDatabase(LINKDB_NAME, dbConfig); + _bridgeDb = openDatabase(BRIDGEDB_NAME, dbConfig); + } + private Database openDatabase(final String dbName, final DatabaseConfig dbConfig) + { + // if opening read-only and the database doesn't exist, then you can't create it + return dbConfig.getReadOnly() && !_environment.getDatabaseNames().contains(dbName) + ? null + : _environment.openDatabase(null, dbName, dbConfig); + } + /** * Called to close and cleanup any resources used by the message store. * @@ -520,10 +543,22 @@ public class BDBMessageStore implements MessageStore _deliveryDb.close(); } + if (_bridgeDb != null) + { + _log.info("Close bridge database"); + _bridgeDb.close(); + } + + if (_linkDb != null) + { + _log.info("Close link database"); + _linkDb.close(); + } + closeEnvironment(); _state = State.CLOSED; - + CurrentActor.get().message(_logSubject,MessageStoreMessages.CLOSED()); } @@ -542,7 +577,7 @@ public class BDBMessageStore implements MessageStore } } - + public void recover(ConfigurationRecoveryHandler recoveryHandler) throws AMQStoreException { stateTransition(State.CONFIGURED, State.RECOVERING); @@ -556,11 +591,12 @@ public class BDBMessageStore implements MessageStore ExchangeRecoveryHandler erh = qrh.completeQueueRecovery(); loadExchanges(erh); - + BindingRecoveryHandler brh = erh.completeExchangeRecovery(); recoverBindings(brh); - - brh.completeBindingRecovery(); + + ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh = brh.completeBindingRecovery(); + recoverBrokerLinks(lrh); } catch (DatabaseException e) { @@ -582,13 +618,13 @@ public class BDBMessageStore implements MessageStore while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS) { QueueRecord queueRecord = (QueueRecord) binding.entryToObject(value); - - String queueName = queueRecord.getNameShortString() == null ? null : + + String queueName = queueRecord.getNameShortString() == null ? null : queueRecord.getNameShortString().asString(); - String owner = queueRecord.getOwner() == null ? null : + String owner = queueRecord.getOwner() == null ? null : queueRecord.getOwner().asString(); boolean exclusive = queueRecord.isExclusive(); - + FieldTable arguments = queueRecord.getArguments(); qrh.queue(queueName, owner, exclusive, arguments); @@ -603,8 +639,8 @@ public class BDBMessageStore implements MessageStore } } } - - + + private void loadExchanges(ExchangeRecoveryHandler erh) throws DatabaseException { Cursor cursor = null; @@ -615,17 +651,17 @@ public class BDBMessageStore implements MessageStore DatabaseEntry key = new DatabaseEntry(); DatabaseEntry value = new DatabaseEntry(); TupleBinding binding = new ExchangeTB(); - + while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS) { ExchangeRecord exchangeRec = (ExchangeRecord) binding.entryToObject(value); - String exchangeName = exchangeRec.getNameShortString() == null ? null : + String exchangeName = exchangeRec.getNameShortString() == null ? null : exchangeRec.getNameShortString().asString(); - String type = exchangeRec.getType() == null ? null : + String type = exchangeRec.getType() == null ? null : exchangeRec.getType().asString(); boolean autoDelete = exchangeRec.isAutoDelete(); - + erh.exchange(exchangeName, type, autoDelete); } } @@ -638,7 +674,7 @@ public class BDBMessageStore implements MessageStore } } - + private void recoverBindings(BindingRecoveryHandler brh) throws DatabaseException { Cursor cursor = null; @@ -648,22 +684,22 @@ public class BDBMessageStore implements MessageStore DatabaseEntry key = new DatabaseEntry(); DatabaseEntry value = new DatabaseEntry(); TupleBinding binding = _bindingTupleBindingFactory.getInstance(); - + while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS) { //yes, this is retrieving all the useful information from the key only. //For table compatibility it shall currently be left as is BindingKey bindingRecord = (BindingKey) binding.entryToObject(key); - + String exchangeName = bindingRecord.getExchangeName() == null ? null : bindingRecord.getExchangeName().asString(); String queueName = bindingRecord.getQueueName() == null ? null : bindingRecord.getQueueName().asString(); String routingKey = bindingRecord.getRoutingKey() == null ? null : bindingRecord.getRoutingKey().asString(); - ByteBuffer argumentsBB = (bindingRecord.getArguments() == null ? null : + ByteBuffer argumentsBB = (bindingRecord.getArguments() == null ? null : java.nio.ByteBuffer.wrap(bindingRecord.getArguments().getDataAsBytes())); - + brh.binding(exchangeName, queueName, routingKey, argumentsBB); } } @@ -677,6 +713,74 @@ public class BDBMessageStore implements MessageStore } + + private void recoverBrokerLinks(final ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh) + { + Cursor cursor = null; + + try + { + cursor = _linkDb.openCursor(null, null); + DatabaseEntry key = new DatabaseEntry(); + DatabaseEntry value = new DatabaseEntry(); + + while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS) + { + UUID id = UUIDTupleBinding.getInstance().entryToObject(key); + long createTime = LongBinding.entryToLong(value); + Map<String,String> arguments = StringMapBinding.getInstance().entryToObject(value); + + ConfigurationRecoveryHandler.BridgeRecoveryHandler brh = lrh.brokerLink(id, createTime, arguments); + + recoverBridges(brh, id); + } + } + finally + { + if (cursor != null) + { + cursor.close(); + } + } + + } + + private void recoverBridges(final ConfigurationRecoveryHandler.BridgeRecoveryHandler brh, final UUID linkId) + { + Cursor cursor = null; + + try + { + cursor = _bridgeDb.openCursor(null, null); + DatabaseEntry key = new DatabaseEntry(); + DatabaseEntry value = new DatabaseEntry(); + + while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS) + { + UUID id = UUIDTupleBinding.getInstance().entryToObject(key); + + UUID parentId = UUIDTupleBinding.getInstance().entryToObject(value); + if(parentId.equals(linkId)) + { + + long createTime = LongBinding.entryToLong(value); + Map<String,String> arguments = StringMapBinding.getInstance().entryToObject(value); + brh.bridge(id,createTime,arguments); + } + } + brh.completeBridgeRecoveryForLink(); + } + finally + { + if (cursor != null) + { + cursor.close(); + } + } + + } + + private void recoverMessages(MessageStoreRecoveryHandler msrh) throws DatabaseException { StoredMessageRecoveryHandler mrh = msrh.begin(); @@ -686,8 +790,6 @@ public class BDBMessageStore implements MessageStore { cursor = _messageMetaDataDb.openCursor(null, null); DatabaseEntry key = new DatabaseEntry(); - EntryBinding keyBinding = TupleBinding.getPrimitiveBinding(Long.class);; - DatabaseEntry value = new DatabaseEntry(); EntryBinding valueBinding = _metaDataTupleBindingFactory.getInstance(); @@ -695,12 +797,12 @@ public class BDBMessageStore implements MessageStore while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS) { - long messageId = (Long) keyBinding.entryToObject(key); + long messageId = LongBinding.entryToLong(key); StorableMessageMetaData metaData = (StorableMessageMetaData) valueBinding.entryToObject(value); StoredBDBMessage message = new StoredBDBMessage(messageId, metaData, false); mrh.message(message); - + maxId = Math.max(maxId, messageId); } @@ -719,14 +821,14 @@ public class BDBMessageStore implements MessageStore } } } - - private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) + + private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) throws DatabaseException { QueueEntryRecoveryHandler qerh = recoveryHandler.begin(this); ArrayList<QueueEntryKey> entries = new ArrayList<QueueEntryKey>(); - + Cursor cursor = null; try { @@ -751,12 +853,12 @@ public class BDBMessageStore implements MessageStore { cursor = null; } - + for(QueueEntryKey entry : entries) { AMQShortString queueName = entry.getQueueName(); long messageId = entry.getMessageId(); - + qerh.queueEntry(queueName.asString(),messageId); } } @@ -781,36 +883,39 @@ public class BDBMessageStore implements MessageStore * * @param messageId Identifies the message to remove. * - * @throws AMQInternalException If the operation fails for any reason. + * @throws AMQStoreException If the operation fails for any reason. */ - public void removeMessage(Long messageId) throws AMQStoreException + public void removeMessage(long messageId) throws AMQStoreException { + removeMessage(messageId, true); + } + public void removeMessage(long messageId, boolean sync) throws AMQStoreException + { + // _log.debug("public void removeMessage(Long messageId = " + messageId): called"); com.sleepycat.je.Transaction tx = null; - + Cursor cursor = null; try { tx = _environment.beginTransaction(null, null); - + //remove the message meta data from the store DatabaseEntry key = new DatabaseEntry(); - EntryBinding metaKeyBindingTuple = TupleBinding.getPrimitiveBinding(Long.class); - metaKeyBindingTuple.objectToEntry(messageId, key); + LongBinding.longToEntry(messageId, key); if (_log.isDebugEnabled()) { _log.debug("Removing message id " + messageId); } - + OperationStatus status = _messageMetaDataDb.delete(tx, key); if (status == OperationStatus.NOTFOUND) { - tx.abort(); - - throw new AMQStoreException("Message metadata not found for message id " + messageId); + _log.info("Message not found (attempt to remove failed - probably application initiated rollback) " + + messageId); } if (_log.isDebugEnabled()) @@ -826,7 +931,7 @@ public class BDBMessageStore implements MessageStore TupleBinding<MessageContentKey> contentKeyTupleBinding = new MessageContentKeyTB_5(); contentKeyTupleBinding.objectToEntry(mck, contentKeyEntry); - //Use a partial record for the value to prevent retrieving the + //Use a partial record for the value to prevent retrieving the //data itself as we only need the key to identify what to remove. DatabaseEntry value = new DatabaseEntry(); value.setPartial(0, 0, true); @@ -837,7 +942,7 @@ public class BDBMessageStore implements MessageStore while (status == OperationStatus.SUCCESS) { mck = (MessageContentKey_5) contentKeyTupleBinding.entryToObject(contentKeyEntry); - + if(mck.getMessageId() != messageId) { //we have exhausted all chunks for this message id, break @@ -846,34 +951,34 @@ public class BDBMessageStore implements MessageStore else { status = cursor.delete(); - + if(status == OperationStatus.NOTFOUND) { cursor.close(); cursor = null; - + tx.abort(); throw new AMQStoreException("Content chunk offset" + mck.getOffset() + " not found for message " + messageId); } - + if (_log.isDebugEnabled()) { _log.debug("Deleted content chunk offset " + mck.getOffset() + " for message " + messageId); } } - + status = cursor.getNext(contentKeyEntry, value, LockMode.RMW); } cursor.close(); cursor = null; - - commit(tx, true); + + commit(tx, sync); } catch (DatabaseException e) { e.printStackTrace(); - + if (tx != null) { try @@ -883,7 +988,7 @@ public class BDBMessageStore implements MessageStore cursor.close(); cursor = null; } - + tx.abort(); } catch (DatabaseException e1) @@ -917,7 +1022,7 @@ public class BDBMessageStore implements MessageStore { if (_state != State.RECOVERING) { - ExchangeRecord exchangeRec = new ExchangeRecord(exchange.getNameShortString(), + ExchangeRecord exchangeRec = new ExchangeRecord(exchange.getNameShortString(), exchange.getTypeShortString(), exchange.isAutoDelete()); DatabaseEntry key = new DatabaseEntry(); @@ -974,20 +1079,20 @@ public class BDBMessageStore implements MessageStore if (_state != State.RECOVERING) { - BindingKey bindingRecord = new BindingKey(exchange.getNameShortString(), + BindingKey bindingRecord = new BindingKey(exchange.getNameShortString(), queue.getNameShortString(), routingKey, args); DatabaseEntry key = new DatabaseEntry(); EntryBinding keyBinding = _bindingTupleBindingFactory.getInstance(); - + keyBinding.objectToEntry(bindingRecord, key); - //yes, this is writing out 0 as a value and putting all the + //yes, this is writing out 0 as a value and putting all the //useful info into the key, don't ask me why. For table //compatibility it shall currently be left as is DatabaseEntry value = new DatabaseEntry(); ByteBinding.byteToEntry((byte) 0, value); - + try { _queueBindingsDb.put(null, key, value); @@ -1043,16 +1148,16 @@ public class BDBMessageStore implements MessageStore { _log.debug("public void createQueue(AMQQueue queue(" + queue.getName() + ") = " + queue + "): called"); } - - QueueRecord queueRecord= new QueueRecord(queue.getNameShortString(), + + QueueRecord queueRecord= new QueueRecord(queue.getNameShortString(), queue.getOwner(), queue.isExclusive(), arguments); - + createQueue(queueRecord); } /** - * Makes the specified queue persistent. - * + * Makes the specified queue persistent. + * * Only intended for direct use during store upgrades. * * @param queueRecord Details of the queue to store. @@ -1086,7 +1191,7 @@ public class BDBMessageStore implements MessageStore /** * Updates the specified queue in the persistent store, IF it is already present. If the queue * is not present in the store, it will not be added. - * + * * NOTE: Currently only updates the exclusivity. * * @param queue The queue to update the entry for. @@ -1112,13 +1217,13 @@ public class BDBMessageStore implements MessageStore OperationStatus status = _queueDb.get(null, key, value, LockMode.DEFAULT); if(status == OperationStatus.SUCCESS) { - //read the existing record and apply the new exclusivity setting + //read the existing record and apply the new exclusivity setting QueueRecord queueRecord = (QueueRecord) queueBinding.entryToObject(value); queueRecord.setExclusive(queue.isExclusive()); - + //write the updated entry to the store queueBinding.objectToEntry(queueRecord, newValue); - + _queueDb.put(null, key, newValue); } else if(status != OperationStatus.NOTFOUND) @@ -1147,7 +1252,7 @@ public class BDBMessageStore implements MessageStore { _log.debug("public void removeQueue(AMQShortString name = " + name + "): called"); } - + DatabaseEntry key = new DatabaseEntry(); EntryBinding keyBinding = new AMQShortStringTB(); keyBinding.objectToEntry(name, key); @@ -1165,6 +1270,90 @@ public class BDBMessageStore implements MessageStore } } + public void createBrokerLink(final BrokerLink link) throws AMQStoreException + { + if (_state != State.RECOVERING) + { + DatabaseEntry key = new DatabaseEntry(); + UUIDTupleBinding.getInstance().objectToEntry(link.getId(), key); + + DatabaseEntry value = new DatabaseEntry(); + LongBinding.longToEntry(link.getCreateTime(),value); + StringMapBinding.getInstance().objectToEntry(link.getArguments(), value); + + try + { + _linkDb.put(null, key, value); + } + catch (DatabaseException e) + { + throw new AMQStoreException("Error writing Link " + link + + " to database: " + e.getMessage(), e); + } + } + } + + public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException + { + DatabaseEntry key = new DatabaseEntry(); + UUIDTupleBinding.getInstance().objectToEntry(link.getId(), key); + try + { + OperationStatus status = _linkDb.delete(null, key); + if (status == OperationStatus.NOTFOUND) + { + throw new AMQStoreException("Link " + link + " not found"); + } + } + catch (DatabaseException e) + { + throw new AMQStoreException("Error deleting the Link " + link + " from database: " + e.getMessage(), e); + } + } + + public void createBridge(final Bridge bridge) throws AMQStoreException + { + if (_state != State.RECOVERING) + { + DatabaseEntry key = new DatabaseEntry(); + UUIDTupleBinding.getInstance().objectToEntry(bridge.getId(), key); + + DatabaseEntry value = new DatabaseEntry(); + UUIDTupleBinding.getInstance().objectToEntry(bridge.getLink().getId(),value); + LongBinding.longToEntry(bridge.getCreateTime(),value); + StringMapBinding.getInstance().objectToEntry(bridge.getArguments(), value); + + try + { + _bridgeDb.put(null, key, value); + } + catch (DatabaseException e) + { + throw new AMQStoreException("Error writing Bridge " + bridge + + " to database: " + e.getMessage(), e); + } + + } + } + + public void deleteBridge(final Bridge bridge) throws AMQStoreException + { + DatabaseEntry key = new DatabaseEntry(); + UUIDTupleBinding.getInstance().objectToEntry(bridge.getId(), key); + try + { + OperationStatus status = _bridgeDb.delete(null, key); + if (status == OperationStatus.NOTFOUND) + { + throw new AMQStoreException("Bridge " + bridge + " not found"); + } + } + catch (DatabaseException e) + { + throw new AMQStoreException("Error deleting the Bridge " + bridge + " from database: " + e.getMessage(), e); + } + } + /** * Places a message onto a specified queue, in a given transaction. * @@ -1174,12 +1363,13 @@ public class BDBMessageStore implements MessageStore * * @throws AMQStoreException If the operation fails for any reason. */ - public void enqueueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue, + long messageId) throws AMQStoreException { // _log.debug("public void enqueueMessage(Transaction tx = " + tx + ", AMQShortString name = " + name + ", Long messageId): called"); - AMQShortString name = new AMQShortString(queue.getResourceName()); - + AMQShortString name = AMQShortString.valueOf(queue.getResourceName()); + DatabaseEntry key = new DatabaseEntry(); EntryBinding keyBinding = new QueueEntryTB(); QueueEntryKey dd = new QueueEntryKey(name, messageId); @@ -1212,7 +1402,8 @@ public class BDBMessageStore implements MessageStore * * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. */ - public void dequeueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue, + long messageId) throws AMQStoreException { AMQShortString name = new AMQShortString(queue.getResourceName()); @@ -1226,7 +1417,7 @@ public class BDBMessageStore implements MessageStore { _log.debug("Dequeue message id " + messageId); } - + try { @@ -1234,7 +1425,7 @@ public class BDBMessageStore implements MessageStore if (status == OperationStatus.NOTFOUND) { throw new AMQStoreException("Unable to find message with id " + messageId + " on queue " + name); - } + } else if (status != OperationStatus.SUCCESS) { throw new AMQStoreException("Unable to remove message with id " + messageId + " on queue " + name); @@ -1269,12 +1460,12 @@ public class BDBMessageStore implements MessageStore //{ // _log.debug("public void commitTranImpl() called with (Transaction=" + tx + ", syncCommit= "+ syncCommit + ")"); //} - + if (tx == null) { throw new AMQStoreException("Fatal internal error: transactional is null at commitTran"); } - + StoreFuture result; try { @@ -1289,7 +1480,7 @@ public class BDBMessageStore implements MessageStore { throw new AMQStoreException("Error commit tx: " + e.getMessage(), e); } - + return result; } @@ -1383,7 +1574,7 @@ public class BDBMessageStore implements MessageStore * * @return A fresh message id. */ - public Long getNewMessageId() + public long getNewMessageId() { return _messageId.incrementAndGet(); } @@ -1398,7 +1589,7 @@ public class BDBMessageStore implements MessageStore * * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. */ - protected void addContent(final com.sleepycat.je.Transaction tx, Long messageId, int offset, + protected void addContent(final com.sleepycat.je.Transaction tx, long messageId, int offset, ByteBuffer contentBody) throws AMQStoreException { DatabaseEntry key = new DatabaseEntry(); @@ -1436,7 +1627,8 @@ public class BDBMessageStore implements MessageStore * * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. */ - private void storeMetaData(final com.sleepycat.je.Transaction tx, Long messageId, StorableMessageMetaData messageMetaData) + private void storeMetaData(final com.sleepycat.je.Transaction tx, long messageId, + StorableMessageMetaData messageMetaData) throws AMQStoreException { if (_log.isDebugEnabled()) @@ -1446,10 +1638,9 @@ public class BDBMessageStore implements MessageStore } DatabaseEntry key = new DatabaseEntry(); - EntryBinding keyBinding = TupleBinding.getPrimitiveBinding(Long.class); - keyBinding.objectToEntry(messageId, key); + LongBinding.longToEntry(messageId, key); DatabaseEntry value = new DatabaseEntry(); - + TupleBinding messageBinding = _metaDataTupleBindingFactory.getInstance(); messageBinding.objectToEntry(messageMetaData, value); try @@ -1475,7 +1666,7 @@ public class BDBMessageStore implements MessageStore * * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. */ - public StorableMessageMetaData getMessageMetaData(Long messageId) throws AMQStoreException + public StorableMessageMetaData getMessageMetaData(long messageId) throws AMQStoreException { if (_log.isDebugEnabled()) { @@ -1484,8 +1675,7 @@ public class BDBMessageStore implements MessageStore } DatabaseEntry key = new DatabaseEntry(); - EntryBinding keyBinding = TupleBinding.getPrimitiveBinding(Long.class); - keyBinding.objectToEntry(messageId, key); + LongBinding.longToEntry(messageId, key); DatabaseEntry value = new DatabaseEntry(); TupleBinding messageBinding = _metaDataTupleBindingFactory.getInstance(); @@ -1519,17 +1709,17 @@ public class BDBMessageStore implements MessageStore * * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. */ - public int getContent(Long messageId, int offset, ByteBuffer dst) throws AMQStoreException - { + public int getContent(long messageId, int offset, ByteBuffer dst) throws AMQStoreException + { DatabaseEntry contentKeyEntry = new DatabaseEntry(); - - //Start from 0 offset and search for the starting chunk. + + //Start from 0 offset and search for the starting chunk. MessageContentKey_5 mck = new MessageContentKey_5(messageId, 0); TupleBinding<MessageContentKey> contentKeyTupleBinding = new MessageContentKeyTB_5(); contentKeyTupleBinding.objectToEntry(mck, contentKeyEntry); DatabaseEntry value = new DatabaseEntry(); TupleBinding<ByteBuffer> contentTupleBinding = new ContentTB(); - + if (_log.isDebugEnabled()) { _log.debug("Message Id: " + messageId + " Getting content body from offset: " + offset); @@ -1537,32 +1727,32 @@ public class BDBMessageStore implements MessageStore int written = 0; int seenSoFar = 0; - + Cursor cursor = null; try { cursor = _messageContentDb.openCursor(null, null); - + OperationStatus status = cursor.getSearchKeyRange(contentKeyEntry, value, LockMode.READ_UNCOMMITTED); while (status == OperationStatus.SUCCESS) { mck = (MessageContentKey_5) contentKeyTupleBinding.entryToObject(contentKeyEntry); long id = mck.getMessageId(); - + if(id != messageId) { //we have exhausted all chunks for this message id, break break; } - + int offsetInMessage = mck.getOffset(); ByteBuffer buf = (ByteBuffer) contentTupleBinding.entryToObject(value); - + final int size = (int) buf.limit(); - + seenSoFar += size; - + if(seenSoFar >= offset) { byte[] dataAsBytes = buf.array(); @@ -1581,7 +1771,7 @@ public class BDBMessageStore implements MessageStore break; } } - + status = cursor.getNext(contentKeyEntry, value, LockMode.RMW); } @@ -1636,7 +1826,7 @@ public class BDBMessageStore implements MessageStore { return _bindingTupleBindingFactory; } - + protected MessageMetaDataTupleBindingFactory getMetaDataTupleBindingFactory() { return _metaDataTupleBindingFactory; @@ -1743,7 +1933,7 @@ public class BDBMessageStore implements MessageStore BDBCommitFuture commitFuture = new BDBCommitFuture(_commitThread, tx, syncCommit); commitFuture.commit(); - + return commitFuture; } @@ -1778,7 +1968,6 @@ public class BDBMessageStore implements MessageStore { _log.debug("public synchronized void complete(): called (Transaction = " + _tx + ")"); } - _complete = true; notifyAll(); @@ -1799,36 +1988,22 @@ public class BDBMessageStore implements MessageStore { //_log.debug("public void commit(): called"); - _commitThread.addJob(this); - + _commitThread.addJob(this, _syncCommit); + if(!_syncCommit) { _log.debug("CommitAsync was requested, returning immediately."); return; } - - synchronized (BDBCommitFuture.this) - { - while (!_complete) - { - try - { - wait(250); - } - catch (InterruptedException e) - { - // _log.error("Unexpected thread interruption: " + e, e); - throw new RuntimeException(e); - } - } - // _log.debug("Commit completed, _databaseException = " + _databaseException); + waitForCompletion(); + // _log.debug("Commit completed, _databaseException = " + _databaseException); - if (_databaseException != null) - { - throw _databaseException; - } + if (_databaseException != null) + { + throw _databaseException; } + } public synchronized boolean isComplete() @@ -1836,10 +2011,11 @@ public class BDBMessageStore implements MessageStore return _complete; } - public void waitForCompletion() + public synchronized void waitForCompletion() { while (!isComplete()) { + _commitThread.explicitNotify(); try { wait(250); @@ -1866,7 +2042,7 @@ public class BDBMessageStore implements MessageStore // private final Logger _log = Logger.getLogger(CommitThread.class); private final AtomicBoolean _stopped = new AtomicBoolean(false); - private final AtomicReference<Queue<BDBCommitFuture>> _jobQueue = new AtomicReference<Queue<BDBCommitFuture>>(new ConcurrentLinkedQueue<BDBCommitFuture>()); + private final Queue<BDBCommitFuture> _jobQueue = new ConcurrentLinkedQueue<BDBCommitFuture>(); private final CheckpointConfig _config = new CheckpointConfig(); private final Object _lock = new Object(); @@ -1877,6 +2053,14 @@ public class BDBMessageStore implements MessageStore } + public void explicitNotify() + { + synchronized (_lock) + { + _lock.notify(); + } + } + public void run() { while (!_stopped.get()) @@ -1887,7 +2071,7 @@ public class BDBMessageStore implements MessageStore { try { - // RHM-7 Periodically wake up and check, just in case we + // RHM-7 Periodically wake up and check, just in case we // missed a notification. Don't want to lock the broker hard. _lock.wait(250); } @@ -1905,24 +2089,24 @@ public class BDBMessageStore implements MessageStore { // _log.debug("private void processJobs(): called"); - // we replace the old queue atomically with a new one and this avoids any need to - // copy elements out of the queue - Queue<BDBCommitFuture> jobs = _jobQueue.getAndSet(new ConcurrentLinkedQueue<BDBCommitFuture>()); + int size = _jobQueue.size(); try { - // _environment.checkpoint(_config); - _environment.sync(); + _environment.flushLog(true); - for (BDBCommitFuture commit : jobs) + for(int i = 0; i < size; i++) { + BDBCommitFuture commit = _jobQueue.poll(); commit.complete(); } + } catch (DatabaseException e) { - for (BDBCommitFuture commit : jobs) + for(int i = 0; i < size; i++) { + BDBCommitFuture commit = _jobQueue.poll(); commit.abort(e); } } @@ -1931,15 +2115,19 @@ public class BDBMessageStore implements MessageStore private boolean hasJobs() { - return !_jobQueue.get().isEmpty(); + return !_jobQueue.isEmpty(); } - public void addJob(BDBCommitFuture commit) + public void addJob(BDBCommitFuture commit, final boolean sync) { - synchronized (_lock) + + _jobQueue.add(commit); + if(sync) { - _jobQueue.get().add(commit); - _lock.notifyAll(); + synchronized (_lock) + { + _lock.notifyAll(); + } } } @@ -1952,14 +2140,17 @@ public class BDBMessageStore implements MessageStore } } } - - + + private class StoredBDBMessage implements StoredMessage { private final long _messageId; private volatile SoftReference<StorableMessageMetaData> _metaDataRef; - private com.sleepycat.je.Transaction _txn; + + private StorableMessageMetaData _metaData; + private volatile SoftReference<byte[]> _dataRef; + private byte[] _data; StoredBDBMessage(long messageId, StorableMessageMetaData metaData) { @@ -1973,22 +2164,15 @@ public class BDBMessageStore implements MessageStore try { _messageId = messageId; + _metaData = metaData; _metaDataRef = new SoftReference<StorableMessageMetaData>(metaData); - if(persist) - { - _txn = _environment.beginTransaction(null, null); - storeMetaData(_txn, messageId, metaData); - } + } catch (DatabaseException e) { throw new RuntimeException(e); } - catch (AMQStoreException e) - { - throw new RuntimeException(e); - } } @@ -2018,58 +2202,114 @@ public class BDBMessageStore implements MessageStore public void addContent(int offsetInMessage, java.nio.ByteBuffer src) { - try + src = src.slice(); + + if(_data == null) { - BDBMessageStore.this.addContent(_txn, _messageId, offsetInMessage, src); + _data = new byte[src.remaining()]; + _dataRef = new SoftReference<byte[]>(_data); + src.duplicate().get(_data); } - catch (AMQStoreException e) + else { - throw new RuntimeException(e); + byte[] oldData = _data; + _data = new byte[oldData.length + src.remaining()]; + _dataRef = new SoftReference<byte[]>(_data); + + System.arraycopy(oldData,0,_data,0,oldData.length); + src.duplicate().get(_data, oldData.length, src.remaining()); } + } public int getContent(int offsetInMessage, java.nio.ByteBuffer dst) { - try + byte[] data = _dataRef == null ? null : _dataRef.get(); + if(data != null) { - return BDBMessageStore.this.getContent(_messageId, offsetInMessage, dst); + int length = Math.min(dst.remaining(), data.length - offsetInMessage); + dst.put(data, offsetInMessage, length); + return length; } - catch (AMQStoreException e) + else { - throw new RuntimeException(e); + try + { + return BDBMessageStore.this.getContent(_messageId, offsetInMessage, dst); + } + catch (AMQStoreException e) + { + throw new RuntimeException(e); + } } } - public StoreFuture flushToStore() + public ByteBuffer getContent(int offsetInMessage, int size) { - try + byte[] data = _dataRef == null ? null : _dataRef.get(); + if(data != null) { - if(_txn != null) - { - //if(_log.isDebugEnabled()) - //{ - // _log.debug("Flushing message " + _messageId + " to store"); - //} - BDBMessageStore.this.commitTranImpl(_txn, true); - } + return ByteBuffer.wrap(data,offsetInMessage,size); } - catch (AMQStoreException e) + else { - throw new RuntimeException(e); + ByteBuffer buf = ByteBuffer.allocate(size); + getContent(offsetInMessage, buf); + buf.position(0); + return buf; } - finally + } + + synchronized void store(com.sleepycat.je.Transaction txn) + { + + if(_metaData != null) { - _txn = null; + try + { + _dataRef = new SoftReference<byte[]>(_data); + BDBMessageStore.this.storeMetaData(txn, _messageId, _metaData); + BDBMessageStore.this.addContent(txn, _messageId, 0, + _data == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(_data)); + } + catch(DatabaseException e) + { + throw new RuntimeException(e); + } + catch (AMQStoreException e) + { + throw new RuntimeException(e); + } + catch (RuntimeException e) + { + e.printStackTrace(); + throw e; + } + finally + { + _metaData = null; + _data = null; + } + } + } + + public synchronized StoreFuture flushToStore() + { + if(_metaData != null) + { + com.sleepycat.je.Transaction txn = _environment.beginTransaction(null, null); + store(txn); + BDBMessageStore.this.commit(txn,true); + } return IMMEDIATE_FUTURE; } public void remove() { - flushToStore(); try { - BDBMessageStore.this.removeMessage(_messageId); + BDBMessageStore.this.removeMessage(_messageId, false); } catch (AMQStoreException e) { @@ -2094,12 +2334,27 @@ public class BDBMessageStore implements MessageStore } } - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException + { + if(message.getStoredMessage() instanceof StoredBDBMessage) + { + ((StoredBDBMessage)message.getStoredMessage()).store(_txn); + } + + BDBMessageStore.this.enqueueMessage(_txn, queue, message.getMessageNumber()); + } + + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException + { + BDBMessageStore.this.dequeueMessage(_txn, queue, message.getMessageNumber()); + } + + public void enqueueMessage(TransactionLogResource queue, long messageId) throws AMQStoreException { BDBMessageStore.this.enqueueMessage(_txn, queue, messageId); } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(TransactionLogResource queue, long messageId) throws AMQStoreException { BDBMessageStore.this.dequeueMessage(_txn, queue, messageId); diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/StringMapBinding.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/StringMapBinding.java new file mode 100644 index 0000000000..f8fd39e127 --- /dev/null +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/StringMapBinding.java @@ -0,0 +1,61 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb; + +import com.sleepycat.bind.tuple.TupleBinding; +import com.sleepycat.bind.tuple.TupleInput; +import com.sleepycat.bind.tuple.TupleOutput; + +import java.util.HashMap; +import java.util.Map; + +public class StringMapBinding extends TupleBinding<Map<String,String>> +{ + + private static final StringMapBinding INSTANCE = new StringMapBinding(); + + public Map<String, String> entryToObject(final TupleInput tupleInput) + { + int entries = tupleInput.readInt(); + Map<String,String> map = new HashMap<String,String>(entries); + for(int i = 0; i < entries; i++) + { + map.put(tupleInput.readString(), tupleInput.readString()); + } + return map; + } + + + public void objectToEntry(final Map<String, String> stringStringMap, final TupleOutput tupleOutput) + { + tupleOutput.writeInt(stringStringMap.size()); + for(Map.Entry<String,String> entry : stringStringMap.entrySet()) + { + tupleOutput.writeString(entry.getKey()); + tupleOutput.writeString(entry.getValue()); + } + } + + public static StringMapBinding getInstance() + { + return INSTANCE; + } +} diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/UUIDTupleBinding.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/UUIDTupleBinding.java new file mode 100644 index 0000000000..c1a5d473f0 --- /dev/null +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/UUIDTupleBinding.java @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb; + +import com.sleepycat.bind.tuple.TupleBinding; +import com.sleepycat.bind.tuple.TupleInput; +import com.sleepycat.bind.tuple.TupleOutput; + +import java.util.UUID; + +public class UUIDTupleBinding extends TupleBinding<UUID> +{ + private static final UUIDTupleBinding INSTANCE = new UUIDTupleBinding(); + + public UUID entryToObject(final TupleInput tupleInput) + { + return new UUID(tupleInput.readLong(), tupleInput.readLong()); + } + + public void objectToEntry(final UUID uuid, final TupleOutput tupleOutput) + { + tupleOutput.writeLong(uuid.getMostSignificantBits()); + tupleOutput.writeLong(uuid.getLeastSignificantBits()); + } + + public static UUIDTupleBinding getInstance() + { + return INSTANCE; + } + + +} diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java index 975e558874..68f1e7ce6f 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java @@ -33,7 +33,7 @@ public class QueueEntryTB extends TupleBinding<QueueEntryKey> public QueueEntryKey entryToObject(TupleInput tupleInput) { AMQShortString queueName = AMQShortStringEncoding.readShortString(tupleInput); - Long messageId = tupleInput.readLong(); + long messageId = tupleInput.readLong(); return new QueueEntryKey(queueName, messageId); } diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java index ef31b78cfe..6c890daaca 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java @@ -32,13 +32,11 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.message.*; import org.apache.qpid.server.store.MessageMetaDataType; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.store.StoredMessage; -import org.apache.qpid.server.store.TransactionLog; import org.apache.qpid.server.store.TransactionLogResource; import org.apache.qpid.transport.DeliveryProperties; import org.apache.qpid.transport.Header; @@ -100,7 +98,7 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto */ MessageProperties msgProps_0_10 = createMessageProperties_0_10(bodySize); DeliveryProperties delProps_0_10 = createDeliveryProperties_0_10(); - Header header_0_10 = new Header(msgProps_0_10, delProps_0_10); + Header header_0_10 = new Header(delProps_0_10, msgProps_0_10); MessageTransfer xfr_0_10 = new MessageTransfer("destination", MessageAcceptMode.EXPLICIT, MessageAcquireMode.PRE_ACQUIRED, header_0_10, completeContentBody_0_10); @@ -162,7 +160,7 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto assertEquals("Message arrival time has changed", origArrivalTime_0_10, returnedMMD_0_10.getArrivalTime()); - DeliveryProperties returnedDelProps_0_10 = returnedMMD_0_10.getHeader().get(DeliveryProperties.class); + DeliveryProperties returnedDelProps_0_10 = returnedMMD_0_10.getHeader().getDeliveryProperties(); assertNotNull("DeliveryProperties were not returned", returnedDelProps_0_10); assertEquals("Immediate flag has changed", delProps_0_10.getImmediate(), returnedDelProps_0_10.getImmediate()); assertEquals("Routing key has changed", delProps_0_10.getRoutingKey(), returnedDelProps_0_10.getRoutingKey()); @@ -170,7 +168,7 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto assertEquals("Message expiration has changed", delProps_0_10.getExpiration(), returnedDelProps_0_10.getExpiration()); assertEquals("Message delivery priority has changed", delProps_0_10.getPriority(), returnedDelProps_0_10.getPriority()); - MessageProperties returnedMsgProps = returnedMMD_0_10.getHeader().get(MessageProperties.class); + MessageProperties returnedMsgProps = returnedMMD_0_10.getHeader().getMessageProperties(); assertNotNull("MessageProperties were not returned", returnedMsgProps); assertTrue("Message correlationID has changed", Arrays.equals(msgProps_0_10.getCorrelationId(), returnedMsgProps.getCorrelationId())); assertEquals("Message content length has changed", msgProps_0_10.getContentLength(), returnedMsgProps.getContentLength()); @@ -352,7 +350,7 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto */ public void testTranCommit() throws Exception { - TransactionLog log = getVirtualHost().getTransactionLog(); + MessageStore log = getVirtualHost().getMessageStore(); BDBMessageStore bdbStore = assertBDBStore(log); @@ -366,10 +364,10 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto } }; - TransactionLog.Transaction txn = log.newTransaction(); + MessageStore.Transaction txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, 1L); - txn.enqueueMessage(mockQueue, 5L); + txn.enqueueMessage(mockQueue, new MockMessage(1L)); + txn.enqueueMessage(mockQueue, new MockMessage(5L)); txn.commitTran(); List<Long> enqueuedIds = bdbStore.getEnqueuedMessages(mockQueueName); @@ -390,7 +388,7 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto */ public void testTranRollbackBeforeCommit() throws Exception { - TransactionLog log = getVirtualHost().getTransactionLog(); + MessageStore log = getVirtualHost().getMessageStore(); BDBMessageStore bdbStore = assertBDBStore(log); @@ -404,14 +402,14 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto } }; - TransactionLog.Transaction txn = log.newTransaction(); + MessageStore.Transaction txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, 21L); + txn.enqueueMessage(mockQueue, new MockMessage(21L)); txn.abortTran(); txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, 22L); - txn.enqueueMessage(mockQueue, 23L); + txn.enqueueMessage(mockQueue, new MockMessage(22L)); + txn.enqueueMessage(mockQueue, new MockMessage(23L)); txn.commitTran(); List<Long> enqueuedIds = bdbStore.getEnqueuedMessages(mockQueueName); @@ -431,7 +429,7 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto */ public void testTranRollbackAfterCommit() throws Exception { - TransactionLog log = getVirtualHost().getTransactionLog(); + MessageStore log = getVirtualHost().getMessageStore(); BDBMessageStore bdbStore = assertBDBStore(log); @@ -445,17 +443,17 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto } }; - TransactionLog.Transaction txn = log.newTransaction(); + MessageStore.Transaction txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, 30L); + txn.enqueueMessage(mockQueue, new MockMessage(30L)); txn.commitTran(); txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, 31L); + txn.enqueueMessage(mockQueue, new MockMessage(31L)); txn.abortTran(); txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, 32L); + txn.enqueueMessage(mockQueue, new MockMessage(32L)); txn.commitTran(); List<Long> enqueuedIds = bdbStore.getEnqueuedMessages(mockQueueName); @@ -467,4 +465,73 @@ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageSto assertEquals("Second Message is incorrect", 32L, val.longValue()); } + private static class MockMessage implements ServerMessage, EnqueableMessage + { + private long _messageId; + + public MockMessage(long messageId) + { + _messageId = messageId; + } + + public String getRoutingKey() + { + return null; + } + + public AMQMessageHeader getMessageHeader() + { + return null; + } + + public StoredMessage getStoredMessage() + { + return null; + } + + public boolean isPersistent() + { + return true; + } + + public long getSize() + { + return 0; + } + + public boolean isImmediate() + { + return false; + } + + public long getExpiration() + { + return 0; + } + + public MessageReference newReference() + { + return null; + } + + public long getMessageNumber() + { + return _messageId; + } + + public long getArrivalTime() + { + return 0; + } + + public int getContent(ByteBuffer buf, int offset) + { + return 0; + } + + public ByteBuffer getContent(int offset, int length) + { + return null; + } + } } diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java index 8e55e79e01..6d7cca59cf 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java @@ -52,7 +52,9 @@ import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl; import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.store.TransactionLogResource; import org.apache.qpid.server.store.berkeleydb.keys.MessageContentKey_4; import org.apache.qpid.server.store.berkeleydb.tuples.MessageContentKeyTupleBindingFactory; @@ -415,7 +417,7 @@ public class BDBUpgradeTest extends QpidBrokerTestCase ContentHeaderBody contentHeaderBody = new ContentHeaderBody(classForBasic, 1, props, bodySize); // add content entry to database - long messageId = store.getNewMessageId(); + final long messageId = store.getNewMessageId(); TupleBinding<MessageContentKey> contentKeyTB = new MessageContentKeyTupleBindingFactory(storeVersion).getInstance(); MessageContentKey contentKey = null; if (storeVersion == VERSION_4) @@ -451,9 +453,29 @@ public class BDBUpgradeTest extends QpidBrokerTestCase return queueName.asString(); } }; - TransactionLog log = (TransactionLog) store; - TransactionLog.Transaction txn = log.newTransaction(); - txn.enqueueMessage(mockQueue, messageId); + + EnqueableMessage mockMessage = new EnqueableMessage() + { + + public long getMessageNumber() + { + return messageId; + } + + public boolean isPersistent() + { + return true; + } + + public StoredMessage getStoredMessage() + { + return null; + } + }; + + MessageStore log = (MessageStore) store; + MessageStore.Transaction txn = log.newTransaction(); + txn.enqueueMessage(mockQueue, mockMessage); txn.commitTran(); } finally diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java index 593c1616fb..b898e85aa2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -111,6 +111,11 @@ public class ManagementExchange implements Exchange, QMFService.Listener } + public void enqueue(ServerMessage message, boolean sync, PostEnqueueAction action) throws AMQException + { + enqueue(message); + } + public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException { enqueue(message); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java index b98daf7cb1..709b59588d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.log4j.Logger; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.transport.codec.BBEncoder; import org.apache.qpid.server.message.ServerMessage; @@ -32,10 +33,14 @@ import org.apache.qpid.AMQException; import org.apache.qpid.management.common.mbeans.ManagedConnection; import java.util.ArrayList; +import java.util.List; public class QMFBrokerRequestCommand extends QMFCommand { + private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf"); + + public QMFBrokerRequestCommand(QMFCommandHeader header, BBDecoder buf) { super(header); @@ -46,6 +51,8 @@ public class QMFBrokerRequestCommand extends QMFCommand String exchangeName = message.getMessageHeader().getReplyToExchange(); String queueName = message.getMessageHeader().getReplyToRoutingKey(); + _qmfLogger.debug("Execute: " + this); + QMFCommand[] commands = new QMFCommand[2]; commands[0] = new QMFBrokerResponseCommand(this, virtualHost); commands[1] = new QMFCommandCompletionCommand(this); @@ -57,7 +64,7 @@ public class QMFBrokerRequestCommand extends QMFCommand QMFMessage responseMessage = new QMFMessage(queueName, cmd); - ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + List<? extends BaseQueue> queues = exchange.route(responseMessage); for(BaseQueue q : queues) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java index 26a27cfa19..64edc2f294 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.log4j.Logger; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.ServerMessage; @@ -31,9 +32,13 @@ import org.apache.qpid.AMQException; import java.util.ArrayList; import java.util.Collection; +import java.util.List; public class QMFClassQueryCommand extends QMFCommand { + private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf"); + + private final String _package; public QMFClassQueryCommand(QMFCommandHeader header, BBDecoder decoder) @@ -47,6 +52,8 @@ public class QMFClassQueryCommand extends QMFCommand String exchangeName = message.getMessageHeader().getReplyToExchange(); String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + _qmfLogger.debug("Execute: " + this); + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); QMFService service = appRegistry.getQMFService(); @@ -71,7 +78,7 @@ public class QMFClassQueryCommand extends QMFCommand Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); - ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + List<? extends BaseQueue> queues = exchange.route(responseMessage); for(BaseQueue q : queues) { @@ -87,4 +94,12 @@ public class QMFClassQueryCommand extends QMFCommand } } + + @Override + public String toString() + { + return "QMFClassQueryCommand{" + + "package='" + _package + '\'' + + '}'; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java index f163e434d1..9a25201d4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java @@ -53,4 +53,13 @@ public class QMFCommandCompletionCommand extends QMFCommand encoder.writeInt32(_status.ordinal()); encoder.writeStr8(_text); } + + @Override + public String toString() + { + return "QMFCommandCompletionCommand{" + + "status=" + _status + + ",text='" + _text + '\'' + + '}'; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java index 8e8cb55a0d..c11e1a9b27 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.log4j.Logger; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.ServerMessage; @@ -33,28 +34,22 @@ import java.util.*; public class QMFGetQueryCommand extends QMFCommand { - private Map<String, Object> _map; + private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf"); + + private String _className; + private String _packageName; + private UUID _objectId; public QMFGetQueryCommand(QMFCommandHeader header, BBDecoder decoder) { super(header); - _map = decoder.readMap(); - } - - public void process(VirtualHost virtualHost, ServerMessage message) - { - String exchangeName = message.getMessageHeader().getReplyToExchange(); - String routingKey = message.getMessageHeader().getReplyToRoutingKey(); - - IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); - QMFService service = appRegistry.getQMFService(); - - String className = (String) _map.get("_class"); - String packageName = (String) _map.get("_package"); + Map<String, Object> _map = decoder.readMap(); + _className = (String) _map.get("_class"); + _packageName = (String) _map.get("_package"); byte[] objectIdBytes = (byte[]) _map.get("_objectId"); - UUID objectId; + if(objectIdBytes != null) { long msb = 0; @@ -68,21 +63,34 @@ public class QMFGetQueryCommand extends QMFCommand { lsb = (lsb << 8) | (objectIdBytes[i] & 0xff); } - objectId = new UUID(msb, lsb); + _objectId = new UUID(msb, lsb); } else { - objectId = null; + _objectId = null; } + + } + + public void process(VirtualHost virtualHost, ServerMessage message) + { + String exchangeName = message.getMessageHeader().getReplyToExchange(); + String routingKey = message.getMessageHeader().getReplyToRoutingKey(); + + IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry(); + QMFService service = appRegistry.getQMFService(); + + _qmfLogger.debug("Execute: " + this); + List<QMFCommand> commands = new ArrayList<QMFCommand>(); final long sampleTime = System.currentTimeMillis() * 1000000l; Collection<QMFPackage> packages; - if(packageName != null && packageName.length() != 0) + if(_packageName != null && _packageName.length() != 0) { - QMFPackage qmfPackage = service.getPackage(packageName); + QMFPackage qmfPackage = service.getPackage(_packageName); if(qmfPackage == null) { packages = Collections.EMPTY_LIST; @@ -102,9 +110,9 @@ public class QMFGetQueryCommand extends QMFCommand Collection<QMFClass> qmfClasses; - if(className != null && className.length() != 0) + if(_className != null && _className.length() != 0) { - QMFClass qmfClass = qmfPackage.getQMFClass(className); + QMFClass qmfClass = qmfPackage.getQMFClass(_className); if(qmfClass == null) { qmfClasses = Collections.EMPTY_LIST; @@ -124,9 +132,9 @@ public class QMFGetQueryCommand extends QMFCommand { Collection<QMFObject> objects; - if(objectId != null) + if(_objectId != null) { - QMFObject obj = service.getObjectById(qmfClass, objectId); + QMFObject obj = service.getObjectById(qmfClass, _objectId); if(obj == null) { objects = Collections.EMPTY_LIST; @@ -158,12 +166,12 @@ public class QMFGetQueryCommand extends QMFCommand for(QMFCommand cmd : commands) { - + _qmfLogger.debug("Respond: " + cmd); QMFMessage responseMessage = new QMFMessage(routingKey, cmd); Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); - ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + List<? extends BaseQueue> queues = exchange.route(responseMessage); for(BaseQueue q : queues) { @@ -179,4 +187,13 @@ public class QMFGetQueryCommand extends QMFCommand } } + @Override + public String toString() + { + return "QMFGetQueryCommand{" + + "packageName='" + _packageName + '\'' + + ", className='" + _className + '\'' + + ", objectId=" + _objectId + + '}'; + } }
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java index 3f6290dedb..3248a5aae0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java @@ -21,14 +21,17 @@ package org.apache.qpid.qmf; +import org.apache.commons.lang.NotImplementedException; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.message.*; +import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.transport.codec.BBEncoder; import java.nio.ByteBuffer; import java.util.Set; -public class QMFMessage implements ServerMessage<QMFMessage>, InboundMessage, AMQMessageHeader +public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHeader { private ByteBuffer _content; @@ -59,11 +62,21 @@ public class QMFMessage implements ServerMessage<QMFMessage>, InboundMessage, AM return _routingKey; } + public AMQShortString getRoutingKeyShortString() + { + return AMQShortString.valueOf(_routingKey); + } + public AMQMessageHeader getMessageHeader() { return this; } + public StoredMessage getStoredMessage() + { + throw new NotImplementedException(); + } + public boolean isPersistent() { return false; @@ -159,9 +172,9 @@ public class QMFMessage implements ServerMessage<QMFMessage>, InboundMessage, AM return new QMFMessageReference(this); } - public Long getMessageNumber() + public long getMessageNumber() { - return null; + return 0l; } public long getArrivalTime() @@ -172,9 +185,9 @@ public class QMFMessage implements ServerMessage<QMFMessage>, InboundMessage, AM public int getContent(ByteBuffer buf, int offset) { ByteBuffer src = _content.duplicate(); - _content.position(offset); - _content = _content.slice(); - int len = _content.remaining(); + src.position(offset); + src = src.slice(); + int len = src.remaining(); if(len > buf.remaining()) { len = buf.remaining(); @@ -185,6 +198,16 @@ public class QMFMessage implements ServerMessage<QMFMessage>, InboundMessage, AM return len; } + + public ByteBuffer getContent(int offset, int size) + { + ByteBuffer src = _content.duplicate(); + src.position(offset); + src = src.slice(); + src.limit(size); + return src; + } + private static class QMFMessageReference extends MessageReference<QMFMessage> { public QMFMessageReference(QMFMessage message) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java index cf27e4b970..4001a2a321 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.qmf; +import org.apache.log4j.Logger; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.ServerMessage; @@ -27,11 +28,14 @@ import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.AMQException; +import java.util.List; import java.util.UUID; import java.util.ArrayList; public class QMFMethodRequestCommand extends QMFCommand { + private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf"); + private QMFMethodInvocation _methodInstance; private QMFObject _object; @@ -58,6 +62,9 @@ public class QMFMethodRequestCommand extends QMFCommand String queueName = message.getMessageHeader().getReplyToRoutingKey(); QMFCommand[] commands = new QMFCommand[2]; + + _qmfLogger.debug("Execute: " + _methodInstance + " on " + _object); + commands[0] = _methodInstance.execute(_object, this); commands[1] = new QMFCommandCompletionCommand(this); @@ -68,7 +75,7 @@ public class QMFMethodRequestCommand extends QMFCommand QMFMessage responseMessage = new QMFMessage(queueName, cmd); - ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + List<? extends BaseQueue> queues = exchange.route(responseMessage); for(BaseQueue q : queues) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java index d126717fc8..631bd3c7cc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java @@ -73,4 +73,9 @@ public abstract class QMFObject<C extends QMFClass, D extends QMFObject.Delegate abstract public QMFCommand asInstrumentInfoCmd(long sampleTime); abstract public QMFCommand asGetQueryResponseCmd(final QMFGetQueryCommand queryCommand, long sampleTime); + @Override + public String toString() + { + return _delegate.toString(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java index 6defd088de..9cacbafcc1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.log4j.Logger; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.ServerMessage; @@ -31,9 +32,13 @@ import org.apache.qpid.AMQException; import java.util.ArrayList; import java.util.Collection; +import java.util.List; public class QMFPackageQueryCommand extends QMFCommand { + + private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf"); + public QMFPackageQueryCommand(QMFCommandHeader header, BBDecoder decoder) { super(header); @@ -52,6 +57,8 @@ public class QMFPackageQueryCommand extends QMFCommand QMFCommand[] commands = new QMFCommand[ supportedSchemas.size() + 1 ]; + _qmfLogger.debug("Exectuting " + this); + int i = 0; for(QMFPackage p : supportedSchemas) { @@ -67,7 +74,7 @@ public class QMFPackageQueryCommand extends QMFCommand Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName); - ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + List<? extends BaseQueue> queues = exchange.route(responseMessage); for(BaseQueue q : queues) @@ -83,4 +90,9 @@ public class QMFPackageQueryCommand extends QMFCommand } } } + + public String toString() + { + return "QMFPackageQueryCommand"; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java index 3141676f10..a1260ed9e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java @@ -21,6 +21,7 @@ package org.apache.qpid.qmf; +import org.apache.log4j.Logger; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.message.ServerMessage; @@ -31,9 +32,12 @@ import org.apache.qpid.AMQException; import java.util.Collection; import java.util.ArrayList; +import java.util.List; public class QMFSchemaRequestCommand extends QMFCommand { + private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf"); + private final String _packageName; private final String _className; private final byte[] _hash; @@ -48,6 +52,8 @@ public class QMFSchemaRequestCommand extends QMFCommand public void process(VirtualHost virtualHost, ServerMessage message) { + _qmfLogger.debug("Execute: " + this); + String exchangeName = message.getMessageHeader().getReplyToExchange(); String routingKey = message.getMessageHeader().getReplyToRoutingKey(); @@ -70,7 +76,7 @@ public class QMFSchemaRequestCommand extends QMFCommand QMFMessage responseMessage = new QMFMessage(routingKey, cmd); - ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage); + List<? extends BaseQueue> queues = exchange.route(responseMessage); for(BaseQueue q : queues) { @@ -85,4 +91,13 @@ public class QMFSchemaRequestCommand extends QMFCommand } } } + + @Override + public String toString() + { + return "QMFSchemaRequestCommand{" + + " packageName='" + _packageName + '\'' + + ", className='" + _className + '\'' + + '}'; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 6abef6fd6b..27345f0a88 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -410,7 +410,10 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable ConcurrentHashMap<UUID, QMFObject> map = _managedObjectsById.get(qmfclass); if(map != null) { - return map.get(id); + + UUID key = new UUID(id.getMostSignificantBits() & (0xFFFl << 48), id.getLeastSignificantBits()); + return map.get(key); + } else { @@ -604,6 +607,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class BrokerDelegate implements BrokerSchema.BrokerDelegate @@ -762,6 +770,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class VhostDelegate implements BrokerSchema.VhostDelegate @@ -797,6 +810,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class ExchangeDelegate implements BrokerSchema.ExchangeDelegate @@ -923,6 +941,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class QueueDelegate implements BrokerSchema.QueueDelegate @@ -1163,6 +1186,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class BindingDelegate implements BrokerSchema.BindingDelegate @@ -1214,6 +1242,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class ConnectionDelegate implements BrokerSchema.ConnectionDelegate @@ -1352,6 +1385,12 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable // TODO return 0; } + + + public String toString() + { + return _obj.toString(); + } } private class SessionDelegate implements BrokerSchema.SessionDelegate @@ -1476,6 +1515,11 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + public String toString() + { + return _obj.toString(); + } } private class SubscriptionDelegate implements BrokerSchema.SubscriptionDelegate @@ -1542,93 +1586,103 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } - } - private class BridgeDelegate implements BrokerSchema.BridgeDelegate + public String toString() { - private final BridgeConfig _obj; + return _obj.toString(); + } + } - private BridgeDelegate(final BridgeConfig obj) - { - _obj = obj; - } + private class BridgeDelegate implements BrokerSchema.BridgeDelegate + { + private final BridgeConfig _obj; - public BrokerSchema.LinkObject getLinkRef() - { - return (BrokerSchema.LinkObject) adapt(_obj.getLink()); - } + private BridgeDelegate(final BridgeConfig obj) + { + _obj = obj; + } - public Integer getChannelId() - { - return _obj.getChannelId(); - } + public BrokerSchema.LinkObject getLinkRef() + { + return (BrokerSchema.LinkObject) adapt(_obj.getLink()); + } - public Boolean getDurable() - { - return _obj.isDurable(); - } + public Integer getChannelId() + { + return _obj.getChannelId(); + } - public String getSrc() - { - return _obj.getSource(); - } + public Boolean getDurable() + { + return _obj.isDurable(); + } - public String getDest() - { - return _obj.getDestination(); - } + public String getSrc() + { + return _obj.getSource(); + } - public String getKey() - { - return _obj.getKey(); - } + public String getDest() + { + return _obj.getDestination(); + } - public Boolean getSrcIsQueue() - { - return _obj.isQueueBridge(); - } + public String getKey() + { + return _obj.getKey(); + } - public Boolean getSrcIsLocal() - { - return _obj.isLocalSource(); - } + public Boolean getSrcIsQueue() + { + return _obj.isQueueBridge(); + } - public String getTag() - { - return _obj.getTag(); - } + public Boolean getSrcIsLocal() + { + return _obj.isLocalSource(); + } - public String getExcludes() - { - return _obj.getExcludes(); - } + public String getTag() + { + return _obj.getTag(); + } - public Boolean getDynamic() - { - return _obj.isDynamic(); - } + public String getExcludes() + { + return _obj.getExcludes(); + } - public Integer getSync() - { - return _obj.getAckBatching(); - } + public Boolean getDynamic() + { + return _obj.isDynamic(); + } - public BrokerSchema.BridgeClass.CloseMethodResponseCommand close(final BrokerSchema.BridgeClass.CloseMethodResponseCommandFactory factory) - { - return null; - } + public Integer getSync() + { + return _obj.getAckBatching(); + } - public UUID getId() - { - return _obj.getId(); - } + public BrokerSchema.BridgeClass.CloseMethodResponseCommand close(final BrokerSchema.BridgeClass.CloseMethodResponseCommandFactory factory) + { + return null; + } - public long getCreateTime() - { - return _obj.getCreateTime(); - } + public UUID getId() + { + return _obj.getId(); } + public long getCreateTime() + { + return _obj.getCreateTime(); + } + + public String toString() + { + return _obj.toString(); + } + } + private class LinkDelegate implements BrokerSchema.LinkDelegate { private final LinkConfig _obj; @@ -1665,14 +1719,12 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable public String getState() { - // TODO - return ""; + return _obj.getState(); } public String getLastError() { - // TODO - return ""; + return _obj.getLastError(); } public BrokerSchema.LinkClass.CloseMethodResponseCommand close(final BrokerSchema.LinkClass.CloseMethodResponseCommandFactory factory) @@ -1706,6 +1758,12 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable { return _obj.getCreateTime(); } + + @Override + public String toString() + { + return _obj.toString(); + } } } 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 30d620401f..873c846258 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 @@ -96,7 +96,7 @@ import java.util.concurrent.atomic.AtomicLong; public class AMQChannel implements SessionConfig, AMQSessionModel { - public static final int DEFAULT_PREFETCH = 5000; + public static final int DEFAULT_PREFETCH = 4096; private static final Logger _logger = Logger.getLogger(AMQChannel.class); @@ -167,6 +167,8 @@ public class AMQChannel implements SessionConfig, AMQSessionModel private final UUID _id; private long _createTime = System.currentTimeMillis(); + private final ClientDeliveryMethod _clientDeliveryMethod; + public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore) throws AMQException { @@ -184,6 +186,8 @@ public class AMQChannel implements SessionConfig, AMQSessionModel // by default the session is non-transactional _transaction = new AutoCommitTransaction(_messageStore); + + _clientDeliveryMethod = session.createDeliveryMethod(_channelId); } public ConfigStore getConfigStore() @@ -206,6 +210,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return !(_transaction instanceof AutoCommitTransaction); } + public void receivedComplete() + { + } + + public boolean inTransaction() { return isTransactional() && _txnUpdateTime.get() > 0 && _transaction.getTransactionStartTime() > 0; @@ -285,7 +294,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel _currentMessage.setExpiration(); - MessageMetaData mmd = _currentMessage.headersReceived(); + MessageMetaData mmd = _currentMessage.headersReceived(getProtocolSession().getLastReceivedTime()); final StoredMessage<MessageMetaData> handle = _messageStore.addMessage(mmd); _currentMessage.setStoredMessage(handle); @@ -317,8 +326,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { try { - _currentMessage.getStoredMessage().flushToStore(); - final ArrayList<? extends BaseQueue> destinationQueues = _currentMessage.getDestinationQueues(); + final List<? extends BaseQueue> destinationQueues = _currentMessage.getDestinationQueues(); if(!checkMessageUserId(_currentMessage.getContentHeader())) { @@ -340,11 +348,13 @@ public class AMQChannel implements SessionConfig, AMQSessionModel } else { - _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues, isTransactional())); + _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues), getProtocolSession().getLastReceivedTime()); incrementOutstandingTxnsIfNecessary(); updateTransactionalActivity(); } } + _currentMessage.getStoredMessage().flushToStore(); + } finally { @@ -858,10 +868,8 @@ public class AMQChannel implements SessionConfig, AMQSessionModel 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(); + return _unacknowledgedMessageMap.acknowledge(deliveryTag, multiple); + } /** @@ -950,12 +958,17 @@ public class AMQChannel implements SessionConfig, AMQSessionModel public void commit() throws AMQException { + commit(null); + } + public void commit(Runnable immediateAction) throws AMQException + { + if (!isTransactional()) { throw new AMQException("Fatal error: commit called on non-transactional channel"); } - _transaction.commit(); + _transaction.commit(immediateAction); _txnCommits.incrementAndGet(); _txnStarts.incrementAndGet(); @@ -1034,7 +1047,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { if (isTransactional()) { - _txnUpdateTime.set(System.currentTimeMillis()); + _txnUpdateTime.set(getProtocolSession().getLastReceivedTime()); } } @@ -1080,21 +1093,6 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return _messageStore; } - private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod() - { - - public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag) - throws AMQException - { - _session.registerMessageDelivered(entry.getMessage().getSize()); - getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(), - deliveryTag, - ((SubscriptionImpl)sub).getConsumerTag()); - entry.incrementDeliveryCount(); - } - - }; - public ClientDeliveryMethod getClientDeliveryMethod() { return _clientDeliveryMethod; @@ -1160,11 +1158,10 @@ public class AMQChannel implements SessionConfig, AMQSessionModel private class MessageDeliveryAction implements ServerTransaction.Action { private IncomingMessage _incommingMessage; - private ArrayList<? extends BaseQueue> _destinationQueues; + private List<? extends BaseQueue> _destinationQueues; public MessageDeliveryAction(IncomingMessage currentMessage, - ArrayList<? extends BaseQueue> destinationQueues, - boolean transactional) + List<? extends BaseQueue> destinationQueues) { _incommingMessage = currentMessage; _destinationQueues = destinationQueues; @@ -1179,8 +1176,10 @@ public class AMQChannel implements SessionConfig, AMQSessionModel final AMQMessage amqMessage = createAMQMessage(_incommingMessage); MessageReference ref = amqMessage.newReference(); - for(final BaseQueue queue : _destinationQueues) + for(int i = 0; i < _destinationQueues.size(); i++) { + BaseQueue queue = _destinationQueues.get(i); + BaseQueue.PostEnqueueAction action; if(immediate) @@ -1192,7 +1191,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel action = null; } - queue.enqueue(amqMessage, action); + queue.enqueue(amqMessage, isTransactional(), action); if(queue instanceof AMQQueue) { @@ -1200,6 +1199,8 @@ public class AMQChannel implements SessionConfig, AMQSessionModel } } + + _incommingMessage.getStoredMessage().flushToStore(); ref.release(); } catch (AMQException e) @@ -1541,7 +1542,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel final InboundMessage m = new InboundMessageAdapter(rejectedQueueEntry); - final ArrayList<? extends BaseQueue> destinationQueues = altExchange.route(m); + final List<? extends BaseQueue> destinationQueues = altExchange.route(m); if (destinationQueues == null || destinationQueues.isEmpty()) { 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 9da02e0600..9765636c25 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 @@ -22,8 +22,8 @@ package org.apache.qpid.server; import org.apache.qpid.server.ack.UnacknowledgedMessageMap; import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.subscription.Subscription; -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; @@ -39,13 +39,13 @@ public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor private final Map<Long, QueueEntry> _msgToResend; private final boolean _requeueIfUnabletoResend; private final UnacknowledgedMessageMap _unacknowledgedMessageMap; - private final TransactionLog _transactionLog; + private final MessageStore _transactionLog; public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap, Map<Long, QueueEntry> msgToRequeue, Map<Long, QueueEntry> msgToResend, boolean requeueIfUnabletoResend, - TransactionLog txnLog) + MessageStore txnLog) { _unacknowledgedMessageMap = unacknowledgedMessageMap; _msgToRequeue = msgToRequeue; 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 0c038c7800..2bfdd93030 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -27,6 +27,7 @@ import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; +import org.apache.log4j.Logger; import org.apache.qpid.server.Broker.InitException; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -230,11 +231,77 @@ public class Main { parsePortArray(options, commandLine.getOptionValues(pe.getExcludeName()), pe); } - } + } + + setExceptionHandler(); startBroker(options); } + protected void setExceptionHandler() + { + Thread.UncaughtExceptionHandler handler = null; + String handlerClass = System.getProperty("qpid.broker.exceptionHandler"); + if(handlerClass != null) + { + try + { + handler = (Thread.UncaughtExceptionHandler) Class.forName(handlerClass).newInstance(); + } + catch (ClassNotFoundException e) + { + + } + catch (InstantiationException e) + { + + } + catch (IllegalAccessException e) + { + + } + catch (ClassCastException e) + { + + } + } + + if(handler == null) + { + handler = + new Thread.UncaughtExceptionHandler() + { + public void uncaughtException(final Thread t, final Throwable e) + { + try + { + System.err.println("########################################################################"); + System.err.println("#"); + System.err.print("# Unhandled Exception "); + System.err.print(e.toString()); + System.err.print(" in Thread "); + System.err.println(t.getName()); + System.err.println("#"); + System.err.println("# Exiting"); + System.err.println("#"); + System.err.println("########################################################################"); + e.printStackTrace(System.err); + + Logger logger = Logger.getLogger("org.apache.qpid.server.Main"); + logger.error("Uncaught exception, shutting down.", e); + } + finally + { + Runtime.getRuntime().halt(1); + } + + } + }; + + Thread.setDefaultUncaughtExceptionHandler(handler); + } + } + protected void startBroker(final BrokerOptions options) throws Exception { Broker broker = new Broker(); 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 3bad73d86d..f4b4932744 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 @@ -46,10 +46,6 @@ public interface UnacknowledgedMessageMap void add(long deliveryTag, QueueEntry message); - void collect(long deliveryTag, boolean multiple, Map<Long, QueueEntry> msgs); - - void remove(Map<Long,QueueEntry> msgs); - QueueEntry remove(long deliveryTag); Collection<QueueEntry> cancelAllMessages(); @@ -67,6 +63,8 @@ public interface UnacknowledgedMessageMap */ Set<Long> getDeliveryTags(); + Collection<QueueEntry> acknowledge(long deliveryTag, boolean multiple); + } 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 d920d97c1a..6a5d863526 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 @@ -157,6 +157,14 @@ public class UnacknowledgedMessageMapImpl implements UnacknowledgedMessageMap } } + public Collection<QueueEntry> acknowledge(long deliveryTag, boolean multiple) + { + Map<Long, QueueEntry> ackedMessageMap = new LinkedHashMap<Long,QueueEntry>(); + collect(deliveryTag, multiple, ackedMessageMap); + remove(ackedMessageMap); + return ackedMessageMap.values(); + } + private void collect(long key, Map<Long, QueueEntry> msgs) { synchronized (_lock) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java index 60c9a86b76..48f85d9bc9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java @@ -115,4 +115,9 @@ public class Binding return result; } + public String toString() + { + return "Binding{bindingKey="+_bindingKey+", exchange="+_exchange+", queue="+_queue+"}"; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java index 0e03e33be8..4e031f0a84 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java @@ -40,7 +40,10 @@ public class ConfigStore private AtomicReference<SystemConfig> _root = new AtomicReference<SystemConfig>(null); private final AtomicLong _objectIdSource = new AtomicLong(0l); + private final AtomicLong _persistentObjectIdSource = new AtomicLong(0l); + // TODO - should load/increment this on broker startup + private long _sequenceNumber = 1L; public enum Event { @@ -167,9 +170,23 @@ public class ConfigStore public UUID createId() { - return new UUID(0l, _objectIdSource.getAndIncrement()); + return new UUID(((_sequenceNumber & 0xFFFl)<<48), _objectIdSource.incrementAndGet()); } + public UUID createPersistentId() + { + return new UUID(0L, _persistentObjectIdSource.incrementAndGet()); + } + + public void persistentIdInUse(UUID id) + { + long lsb = id.getLeastSignificantBits(); + long currentId; + while((currentId = _persistentObjectIdSource.get()) < lsb) + { + _persistentObjectIdSource.compareAndSet(currentId, lsb); + } + } public SystemConfig getRoot() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java index 5a6159df34..0b3a9076dd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java @@ -54,4 +54,8 @@ public interface LinkConfig extends ConfiguredObject<LinkConfigType, LinkConfig> String src, String dest, String key, String tag, String excludes); + + String getState(); + + String getLastError(); }
\ No newline at end of file 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 4b42e39aa1..d3b89649c7 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 @@ -89,7 +89,6 @@ public class ServerConfiguration extends ConfigurationPlugin envVarMap.put("QPID_PORT", "connector.port"); envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers"); envVarMap.put("QPID_SSLPORT", "connector.ssl.port"); - envVarMap.put("QPID_WRITEBIASED", "advanced.useWriteBiasedPool"); envVarMap.put("QPID_JMXPORT_REGISTRYSERVER", MGMT_JMXPORT_REGISTRYSERVER); envVarMap.put("QPID_JMXPORT_CONNECTORSERVER", MGMT_JMXPORT_CONNECTORSERVER); envVarMap.put("QPID_FRAMESIZE", "advanced.framesize"); @@ -736,11 +735,6 @@ public class ServerConfiguration extends ConfigurationPlugin return getStringValue("connector.ssl.certType", "SunX509"); } - public boolean getUseBiasedWrites() - { - return getBooleanValue("advanced.useWriteBiasedPool"); - } - public String getDefaultVirtualHost() { return getStringValue("virtualhosts.default"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index d693c6962b..5ff90b3499 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 @@ -351,11 +351,11 @@ public abstract class AbstractExchange implements Exchange, Managable - public final ArrayList<? extends BaseQueue> route(final InboundMessage message) + public final List<? extends BaseQueue> route(final InboundMessage message) { _receivedMessageCount.incrementAndGet(); _receivedMessageSize.addAndGet(message.getSize()); - final ArrayList<? extends BaseQueue> queues = doRoute(message); + final List<? extends BaseQueue> queues = doRoute(message); if(!queues.isEmpty()) { _routedMessageCount.incrementAndGet(); @@ -364,7 +364,7 @@ public abstract class AbstractExchange implements Exchange, Managable return queues; } - protected abstract ArrayList<? extends BaseQueue> doRoute(final InboundMessage message); + protected abstract List<? extends BaseQueue> doRoute(final InboundMessage message); public long getMsgReceives() { 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 cb0d8ecf8f..8c0a5001db 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -34,6 +34,8 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import javax.management.JMException; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; @@ -41,8 +43,52 @@ public class DirectExchange extends AbstractExchange { private static final Logger _logger = Logger.getLogger(DirectExchange.class); - private final ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>> _bindingsByKey = - new ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>>(); + private static final class BindingSet + { + private CopyOnWriteArraySet<Binding> _bindings = new CopyOnWriteArraySet<Binding>(); + private List<BaseQueue> _queues = new ArrayList<BaseQueue>(); + + public synchronized void addBinding(Binding binding) + { + _bindings.add(binding); + recalculateQueues(); + } + + + public synchronized void removeBinding(Binding binding) + { + _bindings.remove(binding); + recalculateQueues(); + } + + private void recalculateQueues() + { + List<BaseQueue> queues = new ArrayList<BaseQueue>(_bindings.size()); + + for(Binding b : _bindings) + { + if(!queues.contains(b.getQueue())) + { + queues.add(b.getQueue()); + } + } + _queues = queues; + } + + + public List<BaseQueue> getQueues() + { + return _queues; + } + + public CopyOnWriteArraySet<Binding> getBindings() + { + return _bindings; + } + } + + private final ConcurrentHashMap<String, BindingSet> _bindingsByKey = + new ConcurrentHashMap<String, BindingSet>(); public static final ExchangeType<DirectExchange> TYPE = new ExchangeType<DirectExchange>() { @@ -91,33 +137,20 @@ public class DirectExchange extends AbstractExchange } - public ArrayList<? extends BaseQueue> doRoute(InboundMessage payload) + public List<? extends BaseQueue> doRoute(InboundMessage payload) { final String routingKey = payload.getRoutingKey(); - CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(routingKey == null ? "" : routingKey); + BindingSet bindings = _bindingsByKey.get(routingKey == null ? "" : routingKey); if(bindings != null) { - final ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(bindings.size()); - - for(Binding binding : bindings) - { - queues.add(binding.getQueue()); - binding.incrementMatches(); - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("Publishing message to queue " + queues); - } - - return queues; + return bindings.getQueues(); } else { - return new ArrayList<BaseQueue>(0); + return Collections.emptyList(); } @@ -132,16 +165,10 @@ public class DirectExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey, AMQQueue queue) { String bindingKey = (routingKey == null) ? "" : routingKey.toString(); - CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey); + BindingSet bindings = _bindingsByKey.get(bindingKey); if(bindings != null) { - for(Binding binding : bindings) - { - if(binding.getQueue().equals(queue)) - { - return true; - } - } + return bindings.getQueues().contains(queue); } return false; @@ -150,22 +177,20 @@ public class DirectExchange extends AbstractExchange public boolean isBound(AMQShortString routingKey) { String bindingKey = (routingKey == null) ? "" : routingKey.toString(); - CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey); - return bindings != null && !bindings.isEmpty(); + BindingSet bindings = _bindingsByKey.get(bindingKey); + return bindings != null && !bindings.getQueues().isEmpty(); } public boolean isBound(AMQQueue queue) { - for (CopyOnWriteArraySet<Binding> bindings : _bindingsByKey.values()) + for (BindingSet bindings : _bindingsByKey.values()) { - for(Binding binding : bindings) + if(bindings.getQueues().contains(queue)) { - if(binding.getQueue().equals(queue)) - { - return true; - } + return true; } + } return false; } @@ -184,19 +209,19 @@ public class DirectExchange extends AbstractExchange assert queue != null; assert routingKey != null; - CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey); + BindingSet bindings = _bindingsByKey.get(bindingKey); if(bindings == null) { - bindings = new CopyOnWriteArraySet<Binding>(); - CopyOnWriteArraySet<Binding> newBindings; + bindings = new BindingSet(); + BindingSet newBindings; if((newBindings = _bindingsByKey.putIfAbsent(bindingKey, bindings)) != null) { bindings = newBindings; } } - bindings.add(binding); + bindings.addBinding(binding); } @@ -204,10 +229,10 @@ public class DirectExchange extends AbstractExchange { assert binding != null; - CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(binding.getBindingKey()); + BindingSet bindings = _bindingsByKey.get(binding.getBindingKey()); if(bindings != null) { - bindings.remove(binding); + bindings.removeBinding(binding); } } 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 29a3611709..29c354feae 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 @@ -36,6 +36,7 @@ import org.apache.qpid.server.configuration.ExchangeConfig; import javax.management.JMException; import java.util.ArrayList; import java.util.Collection; +import java.util.List; public interface Exchange extends ExchangeReferrer, ExchangeConfig { @@ -70,7 +71,7 @@ public interface Exchange extends ExchangeReferrer, ExchangeConfig * * @return list of queues to which to route the message. */ - ArrayList<? extends BaseQueue> route(InboundMessage message); + List<? extends BaseQueue> route(InboundMessage message); /** 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 e523eb24fb..3a8a86e654 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -37,8 +37,11 @@ import org.apache.qpid.server.filter.JMSSelectorFilter; import org.apache.qpid.server.message.InboundMessage; import javax.management.JMException; +import java.sql.Array; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + import java.lang.ref.WeakReference; public class TopicExchange extends AbstractExchange @@ -77,8 +80,6 @@ public class TopicExchange extends AbstractExchange private static final Logger _logger = Logger.getLogger(TopicExchange.class); - - private final TopicParser _parser = new TopicParser(); private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults = @@ -175,7 +176,6 @@ public class TopicExchange extends AbstractExchange _bindings.put(binding, args); } - } private JMSSelectorFilter createSelectorFilter(final FieldTable args) throws AMQInvalidArgumentException @@ -201,14 +201,23 @@ public class TopicExchange extends AbstractExchange public ArrayList<BaseQueue> doRoute(InboundMessage payload) { - final AMQShortString routingKey = payload.getRoutingKey() == null + final AMQShortString routingKey = payload.getRoutingKeyShortString() == null ? AMQShortString.EMPTY_STRING - : new AMQShortString(payload.getRoutingKey()); + : payload.getRoutingKeyShortString(); + + final Collection<AMQQueue> matchedQueues = getMatchedQueues(payload, routingKey); - // The copy here is unfortunate, but not too bad relevant to the amount of - // things created and copied in getMatchedQueues - ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(); - queues.addAll(getMatchedQueues(payload, routingKey)); + ArrayList<BaseQueue> queues; + + if(matchedQueues.getClass() == ArrayList.class) + { + queues = (ArrayList) matchedQueues; + } + else + { + queues = new ArrayList<BaseQueue>(); + queues.addAll(matchedQueues); + } if(queues == null || queues.isEmpty()) { @@ -325,25 +334,28 @@ public class TopicExchange extends AbstractExchange { Collection<TopicMatcherResult> results = _parser.parse(routingKey); - if(results.isEmpty()) + switch(results.size()) { - return Collections.EMPTY_SET; - } - else - { - Collection<AMQQueue> queues = results.size() == 1 ? null : new HashSet<AMQQueue>(); - for(TopicMatcherResult result : results) - { - TopicExchangeResult res = (TopicExchangeResult)result; - - for(Binding b : res.getBindings()) + case 0: + return Collections.EMPTY_SET; + case 1: + TopicMatcherResult[] resultQueues = new TopicMatcherResult[1]; + results.toArray(resultQueues); + return ((TopicExchangeResult)resultQueues[0]).processMessage(message, null); + default: + Collection<AMQQueue> queues = new HashSet<AMQQueue>(); + for(TopicMatcherResult result : results) { - b.incrementMatches(); + TopicExchangeResult res = (TopicExchangeResult)result; + + for(Binding b : res.getBindings()) + { + b.incrementMatches(); + } + + queues = res.processMessage(message, queues); } - - queues = res.processMessage(message, queues); - } - return queues; + return queues; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java index 41dc0d749a..d8b09a7841 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java @@ -39,6 +39,7 @@ public final class TopicExchangeResult implements TopicMatcherResult private final List<Binding> _bindings = new CopyOnWriteArrayList<Binding>(); private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>(); private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>(); + private volatile ArrayList<AMQQueue> _unfilteredQueueList = new ArrayList<AMQQueue>(0); public void addUnfilteredQueue(AMQQueue queue) { @@ -46,6 +47,9 @@ public final class TopicExchangeResult implements TopicMatcherResult if(instances == null) { _unfilteredQueues.put(queue, 1); + ArrayList<AMQQueue> newList = new ArrayList<AMQQueue>(_unfilteredQueueList); + newList.add(queue); + _unfilteredQueueList = newList; } else { @@ -59,6 +63,10 @@ public final class TopicExchangeResult implements TopicMatcherResult if(instances == 1) { _unfilteredQueues.remove(queue); + ArrayList<AMQQueue> newList = new ArrayList<AMQQueue>(_unfilteredQueueList); + newList.remove(queue); + _unfilteredQueueList = newList; + } else { @@ -166,7 +174,7 @@ public final class TopicExchangeResult implements TopicMatcherResult { if(_filteredQueues.isEmpty()) { - return new ArrayList<AMQQueue>(_unfilteredQueues.keySet()); + return _unfilteredQueueList; } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java index 36076cf75b..4446536d4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java @@ -77,7 +77,7 @@ public class TopicMatcherDFAState } if(nextState == null) { - return Collections.EMPTY_SET; + return Collections.EMPTY_LIST; } // Shortcut if we are at a looping terminal state if((nextState == this) && (_nextStateMap.size() == 1) && _nextStateMap.containsKey(TopicWord.ANY_WORD)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java index 2dff45c326..4db6ee3ad2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.federation; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.BridgeConfig; import org.apache.qpid.server.configuration.BridgeConfigType; @@ -44,32 +45,23 @@ import org.apache.qpid.server.transport.ServerSession; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.transport.DeliveryProperties; -import org.apache.qpid.transport.MessageAcceptMode; -import org.apache.qpid.transport.MessageAcquireMode; -import org.apache.qpid.transport.MessageCreditUnit; -import org.apache.qpid.transport.MessageFlowMode; -import org.apache.qpid.transport.MessageReject; -import org.apache.qpid.transport.MessageRejectCode; -import org.apache.qpid.transport.MessageTransfer; -import org.apache.qpid.transport.Option; -import org.apache.qpid.transport.RangeSet; -import org.apache.qpid.transport.Session; -import org.apache.qpid.transport.SessionException; -import org.apache.qpid.transport.SessionListener; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import org.apache.qpid.transport.*; + +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class Bridge implements BridgeConfig { + private static final String DURABLE = "durable"; + private static final String DYNAMIC = "dynamic"; + private static final String SRC_IS_QUEUE = "srcIsQueue"; + private static final String SRC_IS_LOCAL = "srcIsLocal"; + private static final String SOURCE = "source"; + private static final String DESTINATION = "destination"; + private static final String KEY = "key"; + private static final String TAG = "tag"; + private static final String EXCLUDES = "excludes"; private final boolean _durable; private final boolean _dynamic; private final boolean _queueBridge; @@ -113,19 +105,36 @@ public class Bridge implements BridgeConfig _key = key; _tag = tag; _excludes = excludes; - _id = brokerLink.getConfigStore().createId(); + _id = durable ? brokerLink.getConfigStore().createPersistentId() : brokerLink.getConfigStore().createId(); _transaction = new AutoCommitTransaction(getVirtualHost().getMessageStore()); - if(dynamic) + if(durable) { - if(srcIsLocal) + try + { + brokerLink.getVirtualHost().getDurableConfigurationStore().createBridge(this); + } + catch (AMQStoreException e) + { + throw new RuntimeException(e); + } + } + + createDelegate(); + } + + private void createDelegate() + { + if(_dynamic) + { + if(_localSource) { // TODO } else { - if(srcIsQueue) + if(_queueBridge) { // TODO } @@ -137,9 +146,9 @@ public class Bridge implements BridgeConfig } else { - if(srcIsLocal) + if(_localSource) { - if(srcIsQueue) + if(_queueBridge) { _delegate = new StaticQueuePushBridge(); } @@ -150,7 +159,7 @@ public class Bridge implements BridgeConfig } else { - if(srcIsQueue) + if(_queueBridge) { _delegate = new StaticQueuePullBridge(); } @@ -162,6 +171,65 @@ public class Bridge implements BridgeConfig } } + public Bridge(final BrokerLink brokerLink, + final int bridgeNo, + final UUID id, + final long createTime, + final Map<String, String> arguments) + { + _link = brokerLink; + _bridgeNo = bridgeNo; + _id = id; + brokerLink.getConfigStore().persistentIdInUse(id); + _createTime = createTime; + + _durable = Boolean.valueOf(arguments.get(DURABLE)); + _dynamic = Boolean.valueOf(arguments.get(DYNAMIC)); + _queueBridge = Boolean.valueOf(arguments.get(SRC_IS_QUEUE)); + _localSource = Boolean.valueOf(arguments.get(SRC_IS_LOCAL)); + _source = arguments.get(SOURCE); + _destination = arguments.get(DESTINATION); + _key = arguments.get(KEY); + _tag = arguments.get(TAG); + _excludes = arguments.get(EXCLUDES); + + //TODO. + _transaction = new AutoCommitTransaction(getVirtualHost().getMessageStore()); + + + if(_durable) + { + try + { + brokerLink.getVirtualHost().getDurableConfigurationStore().createBridge(this); + } + catch (AMQStoreException e) + { + throw new RuntimeException(e); + } + } + + createDelegate(); + } + + + public Map<String,String> getArguments() + { + Map<String,String> arguments = new HashMap<String, String>(); + + arguments.put(DURABLE, String.valueOf(_durable)); + arguments.put(DYNAMIC, String.valueOf(_dynamic)); + arguments.put(SRC_IS_QUEUE, String.valueOf(_queueBridge)); + arguments.put(SRC_IS_LOCAL, String.valueOf(_localSource)); + arguments.put(SOURCE, _source); + arguments.put(DESTINATION, _destination); + arguments.put(KEY, _key); + arguments.put(TAG, _tag); + arguments.put(EXCLUDES, _excludes); + + return Collections.unmodifiableMap(arguments); + } + public UUID getId() { return _id; @@ -336,6 +404,7 @@ public class Bridge implements BridgeConfig } + private interface BridgeImpl { void setSession(Session session); @@ -365,7 +434,8 @@ public class Bridge implements BridgeConfig // TODO - deal with exchange not existing DeliveryProperties delvProps = null; - if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) + if(xfr.getHeader() != null && (delvProps = xfr.getHeader().getDeliveryProperties()) != null && delvProps.hasTtl() && + !delvProps.hasExpiration()) { delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl()); } @@ -377,7 +447,7 @@ public class Bridge implements BridgeConfig storeMessage.flushToStore(); MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)_session).getReference()); - ArrayList<? extends BaseQueue> queues = exchange.route(message); + List<? extends BaseQueue> queues = exchange.route(message); @@ -391,7 +461,7 @@ public class Bridge implements BridgeConfig { if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT) { - RangeSet rejects = new RangeSet(); + RangeSet rejects = RangeSetFactory.createRangeSet(); rejects.add(xfr.getId()); MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable"); ssn.invoke(reject); @@ -428,7 +498,7 @@ public class Bridge implements BridgeConfig } - private void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues) + private void enqueue(final ServerMessage message, final List<? extends BaseQueue> queues) { _transaction.enqueue(queues,message, new ServerTransaction.Action() { @@ -456,8 +526,7 @@ public class Bridge implements BridgeConfig { // NO-OP } - }); - + }, 0L); } public void exception(final Session session, final SessionException exception) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java index f330e2f708..a8f75d2b9b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.federation; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.common.ServerPropertyNames; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; @@ -29,16 +30,19 @@ import org.apache.qpid.server.configuration.LinkConfig; import org.apache.qpid.server.configuration.LinkConfigType; import org.apache.qpid.server.transport.ServerSession; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.transport.Binary; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.ConnectionException; -import org.apache.qpid.transport.ConnectionListener; -import org.apache.qpid.transport.Session; -import org.apache.qpid.transport.SessionDelegate; -import org.apache.qpid.transport.TransportException; - -import java.util.Map; -import java.util.UUID; +import org.apache.qpid.transport.*; +import org.apache.qpid.util.Strings; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import java.io.IOException; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledThreadPoolExecutor; @@ -55,6 +59,14 @@ public class BrokerLink implements LinkConfig, ConnectionListener private static final ScheduledThreadPoolExecutor _threadPool = new ScheduledThreadPoolExecutor(CORE_POOL_SIZE); + private static final String TRANSPORT = "transport"; + private static final String HOST = "host"; + private static final String PORT = "port"; + private static final String REMOTE_VHOST = "remoteVhost"; + private static final String DURABLE = "durable"; + private static final String AUTH_MECHANISM = "authMechanism"; + private static final String USERNAME = "username"; + private static final String PASSWORD = "password"; private final String _transport; @@ -68,7 +80,7 @@ public class BrokerLink implements LinkConfig, ConnectionListener private final VirtualHost _virtualHost; private UUID _id; private AtomicBoolean _closing = new AtomicBoolean(); - private final long _createTime = System.currentTimeMillis(); + private final long _createTime; private Connection _qpidConnection; private AtomicReference<Thread> _executor = new AtomicReference<Thread>(); private AtomicInteger _bridgeId = new AtomicInteger(); @@ -88,8 +100,10 @@ public class BrokerLink implements LinkConfig, ConnectionListener { doMakeConnection(); } - };; - ; + }; + + + public static enum State { @@ -205,6 +219,44 @@ public class BrokerLink implements LinkConfig, ConnectionListener } }; + public BrokerLink(final VirtualHost virtualHost, UUID id, long createTime, Map<String, String> arguments) + { + _virtualHost = virtualHost; + _id = id; + virtualHost.getConfigStore().persistentIdInUse(id); + _createTime = createTime; + _transport = arguments.get(TRANSPORT); + + _host = arguments.get(HOST); + _port = Integer.parseInt(arguments.get(PORT)); + _remoteVhost = arguments.get(REMOTE_VHOST); + _durable = Boolean.parseBoolean(arguments.get(DURABLE)); + _authMechanism = arguments.get("authMechanism"); + _username = arguments.get("username"); + _password = arguments.get("password"); + + if(_durable) + { + try + { + _virtualHost.getDurableConfigurationStore().createBrokerLink(this); + } + catch (AMQStoreException e) + { + throw new RuntimeException(e); + } + } + + + _qpidConnection = new Connection(); + _connectionConfig = new ConnectionConfigAdapter(); + _qpidConnection.addConnectionListener(this); + + + makeConnection(); + + } + public BrokerLink(final VirtualHost virtualHost, final String transport, @@ -212,10 +264,13 @@ public class BrokerLink implements LinkConfig, ConnectionListener final int port, final String remoteVhost, final boolean durable, - final String authMechanism, final String username, final String password) + final String authMechanism, + final String username, + final String password) { _virtualHost = virtualHost; _transport = transport; + _createTime = System.currentTimeMillis(); _host = host; _port = port; _remoteVhost = remoteVhost; @@ -223,15 +278,42 @@ public class BrokerLink implements LinkConfig, ConnectionListener _authMechanism = authMechanism; _username = username; _password = password; - _id = virtualHost.getConfigStore().createId(); + _id = durable ? virtualHost.getConfigStore().createPersistentId() : virtualHost.getConfigStore().createId(); + + if(durable) + { + try + { + _virtualHost.getDurableConfigurationStore().createBrokerLink(this); + } + catch (AMQStoreException e) + { + throw new RuntimeException(e); + } + } _qpidConnection = new Connection(); _connectionConfig = new ConnectionConfigAdapter(); _qpidConnection.addConnectionListener(this); - makeConnection(); } + public Map<String,String> getArguments() + { + Map<String,String> arguments = new HashMap<String, String>(); + + arguments.put(TRANSPORT, _transport); + arguments.put(HOST, _host); + arguments.put(PORT, String.valueOf(_port)); + arguments.put(REMOTE_VHOST, _remoteVhost); + arguments.put(DURABLE, String.valueOf(_durable)); + arguments.put(AUTH_MECHANISM, _authMechanism); + arguments.put(USERNAME, _username); + arguments.put(PASSWORD, _password); + + return Collections.unmodifiableMap(arguments); + } + private final boolean updateState(State expected, State newState) { return _stateUpdater.compareAndSet(this,expected,newState); @@ -250,9 +332,50 @@ public class BrokerLink implements LinkConfig, ConnectionListener { try { + _qpidConnection.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()) + { + protected SaslClient createSaslClient(List<Object> brokerMechs) throws ConnectionException, + SaslException + { + Map<String,Object> saslProps = new HashMap<String,Object>(); + + + CallbackHandler cbh = new CallbackHandler() + { + public void handle(final Callback[] callbacks) + throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + Callback cb = callbacks[i]; + if (cb instanceof NameCallback) + { + ((NameCallback)cb).setName(_username); + } + else if (cb instanceof PasswordCallback) + { + ((PasswordCallback)cb).setPassword(_password.toCharArray()); + } + else + { + throw new UnsupportedCallbackException(cb); + } + } + + } + }; + final SaslClient sc = Sasl.createSaslClient(new String[] {"PLAIN"}, null, + _conSettings.getSaslProtocol(), + _conSettings.getSaslServerName(), + saslProps, cbh); + + return sc; + }}); + _qpidConnection.connect(_host, _port, _remoteVhost, _username, _password, "ssl".equals(_transport), _authMechanism); final Map<String,Object> serverProps = _qpidConnection.getServerProperties(); + _remoteFederationTag = (String) serverProps.get(ServerPropertyNames.FEDERATION_TAG); if(_remoteFederationTag == null) { @@ -445,6 +568,20 @@ public class BrokerLink implements LinkConfig, ConnectionListener } + public void createBridge(final UUID id, final long createTime, final Map<String, String> arguments) + { + if(!_closing.get()) + { + Bridge bridge = new Bridge(this, _bridgeId.incrementAndGet(), id, createTime, arguments); + if(_bridges.putIfAbsent(bridge, bridge) == null) + { + + addBridge(bridge); + } + } + } + + private void addBridge(final Bridge bridge) { getConfigStore().addConfiguredObject(bridge); @@ -509,4 +646,34 @@ public class BrokerLink implements LinkConfig, ConnectionListener { return _remoteFederationTag; } + + public String getState() + { + return _state.name(); + } + + public String getLastError() + { + return _lastErrorMessage; + } + + @Override + public String toString() + { + return "BrokerLink{" + + " _id=" + _id + + ", _transport='" + _transport + '\'' + + ", _host='" + _host + '\'' + + ", _port=" + _port + + ", _remoteVhost='" + _remoteVhost + '\'' + + ", _durable=" + _durable + + ", _authMechanism='" + _authMechanism + '\'' + + ", _username='" + _username + '\'' + + ", _password='" + _password + '\'' + + ", _virtualHost=" + _virtualHost + + ", _createTime=" + _createTime + + ", _remoteFederationTag='" + _remoteFederationTag + '\'' + + ", _state=" + _state + + '}'; + } } 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 cfe5aedd61..a77ed5700a 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 @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.flow; +import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.Set; import java.util.HashSet; @@ -27,13 +28,16 @@ import java.util.HashSet; public abstract class AbstractFlowCreditManager implements FlowCreditManager { protected final AtomicBoolean _suspended = new AtomicBoolean(false); - private final Set<FlowCreditManagerListener> _listeners = new HashSet<FlowCreditManagerListener>(); + private final ArrayList<FlowCreditManagerListener> _listeners = new ArrayList<FlowCreditManagerListener>(); public final void addStateListener(FlowCreditManagerListener listener) { synchronized(_listeners) { - _listeners.add(listener); + if(!_listeners.contains(listener)) + { + _listeners.add(listener); + } } } @@ -49,9 +53,10 @@ public abstract class AbstractFlowCreditManager implements FlowCreditManager { synchronized(_listeners) { - for(FlowCreditManagerListener listener : _listeners) + final int size = _listeners.size(); + for(int i = 0; i<size; i++) { - listener.creditStateChanged(!suspended); + _listeners.get(i).creditStateChanged(!suspended); } } } 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 765dee2878..8875f21d0b 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 @@ -52,7 +52,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); AMQChannel channel = protocolConnection.getChannel(channelId); - VirtualHost vHost = protocolConnection.getVirtualHost(); if (channel == null) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java index 9133cce6b7..32aa99534b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java @@ -65,7 +65,6 @@ public class ChannelCloseHandler implements StateAwareMethodListener<ChannelClos { throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "Trying to close unknown channel"); } - session.closeChannel(channelId); // Client requested closure so we don't wait for ok we send it stateManager.getProtocolSession().closeChannelOk(channelId); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java index 696ca8a63b..5ccaa49de8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java @@ -55,7 +55,6 @@ public class ChannelFlowHandler implements StateAwareMethodListener<ChannelFlowB { throw body.getChannelNotFoundException(channelId); } - channel.setSuspended(!body.getActive()); _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java index f8e4eab0b6..6eaba87b79 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java @@ -49,7 +49,6 @@ public class ConnectionCloseMethodHandler implements StateAwareMethodListener<Co public void methodReceived(AMQStateManager stateManager, ConnectionCloseBody body, int channelId) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - if (_logger.isInfoEnabled()) { _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" + diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java index ccd42204d9..21aea1510b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java @@ -65,7 +65,6 @@ public class ExchangeBoundHandler implements StateAwareMethodListener<ExchangeBo public void methodReceived(AMQStateManager stateManager, ExchangeBoundBody body, int channelId) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - VirtualHost virtualHost = session.getVirtualHost(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); MethodRegistry methodRegistry = session.getMethodRegistry(); 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 0cfed77f2e..693b316607 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 @@ -85,6 +85,13 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + AMQChannel channel = protocolConnection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + synchronized (queueRegistry) { queue = queueRegistry.getQueue(queueName); @@ -183,12 +190,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar } - AMQChannel channel = protocolConnection.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } //set this as the default queue on the channel: channel.setDefaultQueue(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 da52268e52..902e3ade85 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 @@ -64,15 +64,17 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + + AMQChannel channel = protocolConnection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } + AMQQueue queue; if (body.getQueue() == null) { - AMQChannel channel = protocolConnection.getChannel(channelId); - - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } //get the default queue on the channel: queue = channel.getDefaultQueue(); 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 759eec0129..6c3e11be5b 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 @@ -63,17 +63,14 @@ public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBod QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); AMQChannel channel = protocolConnection.getChannel(channelId); - - + if (channel == null) + { + throw body.getChannelNotFoundException(channelId); + } AMQQueue queue; if(body.getQueue() == null) { - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } - //get the default queue on the channel: queue = channel.getDefaultQueue(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java index f2119f7faa..3849c5af19 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -66,14 +66,15 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB final AMQQueue queue; final AMQShortString routingKey; - if (body.getQueue() == null) + + AMQChannel channel = session.getChannel(channelId); + if (channel == null) { - AMQChannel channel = session.getChannel(channelId); + throw body.getChannelNotFoundException(channelId); + } - if (channel == null) - { - throw body.getChannelNotFoundException(channelId); - } + if (body.getQueue() == null) + { queue = channel.getDefaultQueue(); 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 9b357403a8..885b039e18 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java @@ -22,6 +22,9 @@ package org.apache.qpid.server.logging.subjects; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.transport.ServerConnection; +import org.apache.qpid.server.transport.ServerSession; + import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; public class ChannelLogSubject extends AbstractLogSubject @@ -52,5 +55,33 @@ public class ChannelLogSubject extends AbstractLogSubject session.getVirtualHost().getName(), channel.getChannelId()); } - + + public ChannelLogSubject(ServerSession session) + { + /** + * LOG FORMAT used by the AMQPConnectorActor follows + * ChannelLogSubject.CHANNEL_FORMAT : + * con:{0}({1}@{2}/{3})/ch:{4} + * + * Uses a MessageFormat call to insert the required values according to + * these indices: + * + * 0 - Connection ID + * 1 - User ID + * 2 - IP + * 3 - Virtualhost + * 4 - Channel ID + */ + if(session.getConnection() instanceof ServerConnection) + { + ServerConnection connection = (ServerConnection) session.getConnection(); + setLogStringWithFormat(CHANNEL_FORMAT, + connection == null ? -1L : connection.getConnectionId(), + session.getAuthorizedPrincipal() == null ? "?" : session.getAuthorizedPrincipal().getName(), + (connection == null || connection.getConfig() == null) ? "?" : connection.getConfig().getAddress(), + session.getVirtualHost().getName(), + session.getChannel()); + } + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java index 4fcbaa237e..e36e467fea 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java @@ -37,7 +37,7 @@ import java.nio.ByteBuffer; /** * A deliverable message. */ -public class AMQMessage extends AbstractServerMessageImpl +public class AMQMessage extends AbstractServerMessageImpl<MessageMetaData> { /** Used for debugging purposes. */ private static final Logger _log = Logger.getLogger(AMQMessage.class); @@ -62,9 +62,7 @@ public class AMQMessage extends AbstractServerMessageImpl private Object _sessionIdentifier; private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER); - private final StoredMessage<MessageMetaData> _handle; - - WeakReference<AMQChannel> _channelRef; + private WeakReference<AMQChannel> _channelRef; public AMQMessage(StoredMessage<MessageMetaData> handle) { @@ -75,7 +73,7 @@ public class AMQMessage extends AbstractServerMessageImpl { super(handle); - _handle = handle; + final MessageMetaData metaData = handle.getMetaData(); _size = metaData.getContentSize(); final MessagePublishInfo messagePublishInfo = metaData.getMessagePublishInfo(); @@ -97,7 +95,7 @@ public class AMQMessage extends AbstractServerMessageImpl public MessageMetaData getMessageMetaData() { - return _handle.getMetaData(); + return getStoredMessage().getMetaData(); } public ContentHeaderBody getContentHeaderBody() throws AMQException @@ -107,7 +105,7 @@ public class AMQMessage extends AbstractServerMessageImpl public Long getMessageId() { - return _handle.getMessageNumber(); + return getStoredMessage().getMessageNumber(); } /** @@ -219,9 +217,9 @@ public class AMQMessage extends AbstractServerMessageImpl return new AMQMessageReference(this); } - public Long getMessageNumber() + public long getMessageNumber() { - return getMessageId(); + return getStoredMessage().getMessageNumber(); } @@ -248,16 +246,13 @@ public class AMQMessage extends AbstractServerMessageImpl public int getContent(ByteBuffer buf, int offset) { - return _handle.getContent(offset, buf); + return getStoredMessage().getContent(offset, buf); } - public StoredMessage<MessageMetaData> getStoredMessage() + + public ByteBuffer getContent(int offset, int size) { - return _handle; + return getStoredMessage().getContent(offset, size); } - public SessionConfig getSessionConfig() - { - return _channelRef == null ? null : ((SessionConfig) _channelRef.get()); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java index 80c28332c0..b1d43f0b50 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java @@ -21,19 +21,30 @@ package org.apache.qpid.server.message; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import org.apache.qpid.server.store.StorableMessageMetaData; import org.apache.qpid.server.store.StoredMessage; -public abstract class AbstractServerMessageImpl implements ServerMessage +public abstract class AbstractServerMessageImpl<T extends StorableMessageMetaData> implements ServerMessage<T> { - private final AtomicInteger _referenceCount = new AtomicInteger(0); - private final StoredMessage<?> _handle; - public AbstractServerMessageImpl(StoredMessage<?> handle) + private static final AtomicIntegerFieldUpdater<AbstractServerMessageImpl> _refCountUpdater = + AtomicIntegerFieldUpdater.newUpdater(AbstractServerMessageImpl.class, "_referenceCount"); + + private volatile int _referenceCount = 0; + private final StoredMessage<T> _handle; + + public AbstractServerMessageImpl(StoredMessage<T> handle) { _handle = handle; } + public StoredMessage<T> getStoredMessage() + { + return _handle; + } + public boolean incrementReference() { return incrementReference(1); @@ -41,9 +52,9 @@ public abstract class AbstractServerMessageImpl implements ServerMessage public boolean incrementReference(int count) { - if(_referenceCount.addAndGet(count) <= 0) + if(_refCountUpdater.addAndGet(this, count) <= 0) { - _referenceCount.addAndGet(-count); + _refCountUpdater.addAndGet(this, -count); return false; } else @@ -62,7 +73,7 @@ public abstract class AbstractServerMessageImpl implements ServerMessage */ public void decrementReference() { - int count = _referenceCount.decrementAndGet(); + int count = _refCountUpdater.decrementAndGet(this); // 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 @@ -73,7 +84,7 @@ public abstract class AbstractServerMessageImpl implements ServerMessage // 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); + _refCountUpdater.set(this,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 @@ -99,6 +110,6 @@ public abstract class AbstractServerMessageImpl implements ServerMessage protected int getReferenceCount() { - return _referenceCount.get(); + return _referenceCount; } }
\ No newline at end of file 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 index c32f80fc5b..7be91ad0ca 100755 --- 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 @@ -20,8 +20,11 @@ */ package org.apache.qpid.server.message; +import org.apache.qpid.server.store.StoredMessage; + public interface EnqueableMessage { - Long getMessageNumber(); + long getMessageNumber(); boolean isPersistent(); + StoredMessage getStoredMessage(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java index 1b3fdb1870..79d5574a91 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java @@ -22,10 +22,12 @@ package org.apache.qpid.server.message; import org.apache.qpid.server.queue.Filterable; +import org.apache.qpid.framing.AMQShortString; public interface InboundMessage extends Filterable { String getRoutingKey(); + AMQShortString getRoutingKeyShortString(); AMQMessageHeader getMessageHeader(); 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 index 08a09c4a85..44741f57bd 100755 --- 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 @@ -26,6 +26,7 @@ import java.nio.ByteBuffer; public interface MessageContentSource { public int getContent(ByteBuffer buf, int offset); + public ByteBuffer getContent(int offset, int size); 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 index 5992e42fb7..9bfa0bb2fb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -29,8 +29,8 @@ 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 org.apache.qpid.server.util.ByteBufferInputStream; import org.apache.qpid.server.util.ByteBufferOutputStream; +import org.apache.qpid.util.ByteBufferInputStream; import java.io.*; import java.nio.ByteBuffer; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java index f9863f4945..17ebb6ee07 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java @@ -30,9 +30,12 @@ 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 org.apache.qpid.framing.AMQShortString; import java.nio.ByteBuffer; import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.List; public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMessage { @@ -42,7 +45,6 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes private MessageTransferHeader _messageHeader; private long _arrivalTime; private int _bodySize; - private volatile SoftReference<ByteBuffer> _body; private static final int ENCODER_SIZE = 1 << 10; @@ -53,21 +55,16 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes public MessageMetaData_0_10(MessageTransfer xfr) { - this(xfr.getHeader(), xfr.getBodySize(), xfr.getBody(), System.currentTimeMillis()); + this(xfr.getHeader(), xfr.getBodySize(), 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); + _deliveryProps = _header.getDeliveryProperties(); + _messageProps = _header.getMessageProperties(); } else { @@ -78,21 +75,6 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes _arrivalTime = arrivalTime; _bodySize = bodySize; - - - if(xfrBody == null) - { - _body = null; - } - else - { - ByteBuffer body = ByteBuffer.allocate(_bodySize); - body.put(xfrBody); - body.flip(); - _body = new SoftReference<ByteBuffer>(body); - } - - } @@ -122,16 +104,39 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes encoder.writeInt64(_arrivalTime); encoder.writeInt32(_bodySize); - Struct[] headers = _header == null ? new Struct[0] : _header.getStructs(); - encoder.writeInt32(headers.length); + int headersLength = 0; + if(_header.getDeliveryProperties() != null) + { + headersLength++; + } + if(_header.getMessageProperties() != null) + { + headersLength++; + } + if(_header.getNonStandardProperties() != null) + { + headersLength += _header.getNonStandardProperties().size(); + } + encoder.writeInt32(headersLength); - for(Struct header : headers) + if(_header.getDeliveryProperties() != null) { - encoder.writeStruct32(header); - + encoder.writeStruct32(_header.getDeliveryProperties()); + } + if(_header.getMessageProperties() != null) + { + encoder.writeStruct32(_header.getMessageProperties()); } + if(_header.getNonStandardProperties() != null) + { + for(Struct header : _header.getNonStandardProperties()) + { + encoder.writeStruct32(header); + } + + } ByteBuffer buf = encoder.buffer(); return buf; } @@ -173,6 +178,11 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes return _deliveryProps == null ? null : _deliveryProps.getRoutingKey(); } + public AMQShortString getRoutingKeyShortString() + { + return AMQShortString.valueOf(getRoutingKey()); + } + public AMQMessageHeader getMessageHeader() { return _messageHeader; @@ -210,17 +220,6 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes return _header; } - public ByteBuffer getBody() - { - ByteBuffer body = _body == null ? null : _body.get(); - return body; - } - - public void setBody(ByteBuffer body) - { - _body = new SoftReference<ByteBuffer>(body); - } - private static class MetaDataFactory implements MessageMetaDataType.Factory<MessageMetaData_0_10> { public MessageMetaData_0_10 createMetaData(ByteBuffer buf) @@ -232,14 +231,32 @@ public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMes int bodySize = decoder.readInt32(); int headerCount = decoder.readInt32(); - Struct[] headers = new Struct[headerCount]; + DeliveryProperties deliveryProperties = null; + MessageProperties messageProperties = null; + List<Struct> otherProps = null; for(int i = 0 ; i < headerCount; i++) { - headers[i] = decoder.readStruct32(); + Struct struct = decoder.readStruct32(); + if(struct instanceof DeliveryProperties && deliveryProperties == null) + { + deliveryProperties = (DeliveryProperties) struct; + } + else if(struct instanceof MessageProperties && messageProperties == null) + { + messageProperties = (MessageProperties) struct; + } + else + { + if(otherProps == null) + { + otherProps = new ArrayList<Struct>(); + + } + otherProps.add(struct); + } } - - Header header = new Header(headers); + Header header = new Header(deliveryProperties,messageProperties,otherProps); return new MessageMetaData_0_10(header, bodySize, arrivalTime); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java index d160d91f65..9cb5904bb3 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java @@ -20,25 +20,30 @@ */ package org.apache.qpid.server.message; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.qpid.amqp_1_0.codec.ValueHandler; import org.apache.qpid.amqp_1_0.messaging.SectionDecoder; import org.apache.qpid.amqp_1_0.type.AmqpErrorException; -import org.apache.qpid.amqp_1_0.type.Binary; import org.apache.qpid.amqp_1_0.type.Section; import org.apache.qpid.amqp_1_0.type.Symbol; -import org.apache.qpid.amqp_1_0.type.UnsignedInteger; import org.apache.qpid.amqp_1_0.type.codec.AMQPDescribedTypeRegistry; -import org.apache.qpid.amqp_1_0.type.messaging.*; - - +import org.apache.qpid.amqp_1_0.type.messaging.AmqpSequence; +import org.apache.qpid.amqp_1_0.type.messaging.AmqpValue; +import org.apache.qpid.amqp_1_0.type.messaging.ApplicationProperties; +import org.apache.qpid.amqp_1_0.type.messaging.Data; +import org.apache.qpid.amqp_1_0.type.messaging.DeliveryAnnotations; +import org.apache.qpid.amqp_1_0.type.messaging.Footer; +import org.apache.qpid.amqp_1_0.type.messaging.Header; +import org.apache.qpid.amqp_1_0.type.messaging.MessageAnnotations; import org.apache.qpid.amqp_1_0.type.messaging.Properties; -import org.apache.qpid.configuration.Validator; import org.apache.qpid.server.store.MessageMetaDataType; import org.apache.qpid.server.store.StorableMessageMetaData; -import java.nio.ByteBuffer; -import java.util.*; - public class MessageMetaData_1_0 implements StorableMessageMetaData { // TODO move to somewhere more useful @@ -312,6 +317,18 @@ public class MessageMetaData_1_0 implements StorableMessageMetaData return buf.limit(); } + public int getContentSize() + { + ByteBuffer buf = _encoded; + + if(buf == null) + { + buf = encodeAsBuffer(); + _encoded = buf; + } + return buf.remaining(); + } + public boolean isPersistent() { return _header != null && Boolean.TRUE.equals(_header.getDurable()); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java index 1a230a2590..c4d2a190e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java @@ -24,32 +24,35 @@ import org.apache.qpid.transport.*; import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.transport.ServerSession; +import org.apache.qpid.framing.AMQShortString; import java.nio.ByteBuffer; -import java.lang.ref.WeakReference; -public class MessageTransferMessage extends AbstractServerMessageImpl implements InboundMessage +public class MessageTransferMessage extends AbstractServerMessageImpl<MessageMetaData_0_10> implements InboundMessage { - private StoredMessage<MessageMetaData_0_10> _storeMessage; - private WeakReference<Session> _sessionRef; - public MessageTransferMessage(StoredMessage<MessageMetaData_0_10> storeMessage, WeakReference<Session> sessionRef) + private Object _connectionRef; + + public MessageTransferMessage(StoredMessage<MessageMetaData_0_10> storeMessage, Object connectionRef) { super(storeMessage); - _storeMessage = storeMessage; - _sessionRef = sessionRef; + _connectionRef = connectionRef; } private MessageMetaData_0_10 getMetaData() { - return _storeMessage.getMetaData(); + return getStoredMessage().getMetaData(); } public String getRoutingKey() { return getMetaData().getRoutingKey(); + } + public AMQShortString getRoutingKeyShortString() + { + return AMQShortString.valueOf(getRoutingKey()); } public AMQMessageHeader getMessageHeader() @@ -91,9 +94,9 @@ public class MessageTransferMessage extends AbstractServerMessageImpl implements return new TransferMessageReference(this); } - public Long getMessageNumber() + public long getMessageNumber() { - return _storeMessage.getMessageNumber(); + return getStoredMessage().getMessageNumber(); } public long getArrivalTime() @@ -103,7 +106,13 @@ public class MessageTransferMessage extends AbstractServerMessageImpl implements public int getContent(ByteBuffer buf, int offset) { - return _storeMessage.getContent(offset, buf); + return getStoredMessage().getContent(offset, buf); + } + + + public ByteBuffer getContent(int offset, int size) + { + return getStoredMessage().getContent(offset,size); } public Header getHeader() @@ -113,32 +122,13 @@ public class MessageTransferMessage extends AbstractServerMessageImpl implements public ByteBuffer getBody() { - ByteBuffer body = getMetaData().getBody(); - if(body == null && getSize() != 0l) - { - 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; + return getContent(0, (int)getSize()); } - public Session getSession() + public Object getConnectionReference() { - return _sessionRef == null ? null : _sessionRef.get(); + return _connectionRef; } - public SessionConfig getSessionConfig() - { - return _sessionRef == null ? null : (ServerSession) _sessionRef.get(); - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java index e3cc9879fa..d354d3b145 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java @@ -22,14 +22,17 @@ package org.apache.qpid.server.message; import java.nio.ByteBuffer; -import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.store.StorableMessageMetaData; +import org.apache.qpid.server.store.StoredMessage; -public interface ServerMessage<T extends ServerMessage> extends EnqueableMessage, MessageContentSource +public interface ServerMessage<T extends StorableMessageMetaData> extends EnqueableMessage, MessageContentSource { String getRoutingKey(); AMQMessageHeader getMessageHeader(); + public StoredMessage<T> getStoredMessage(); + boolean isPersistent(); long getSize(); @@ -38,13 +41,14 @@ public interface ServerMessage<T extends ServerMessage> extends EnqueableMessage long getExpiration(); - MessageReference<T> newReference(); + MessageReference newReference(); - Long getMessageNumber(); + long getMessageNumber(); long getArrivalTime(); public int getContent(ByteBuffer buf, int offset); - SessionConfig getSessionConfig(); + public ByteBuffer getContent(int offset, int size); + } 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 index aded3f3d2a..483bca894e 100755 --- 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 @@ -40,8 +40,8 @@ public class HeaderPropertiesConverter BasicContentHeaderProperties props = new BasicContentHeaderProperties(); Header header = messageTransferMessage.getHeader(); - DeliveryProperties deliveryProps = header.get(DeliveryProperties.class); - MessageProperties messageProps = header.get(MessageProperties.class); + DeliveryProperties deliveryProps = header.getDeliveryProperties(); + MessageProperties messageProps = header.getMessageProperties(); if(deliveryProps != null) { 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 3970e5a2d4..efd904f6aa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java @@ -1,420 +1,420 @@ -/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/*
- * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
- * Supported AMQP versions:
- * 8-0
- */
-package org.apache.qpid.server.output.amqp0_8;
-
-import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-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.MessagePublishInfo;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.transport.DeliveryProperties;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
-{
-
- private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
-
- public static Factory getInstanceFactory()
- {
- return new Factory()
- {
-
- public ProtocolOutputConverter newInstance(AMQProtocolSession session)
- {
- return new ProtocolOutputConverterImpl(session);
- }
- };
- }
-
-
- private final AMQProtocolSession _protocolSession;
-
- private ProtocolOutputConverterImpl(AMQProtocolSession session)
- {
- _protocolSession = session;
- }
-
-
- public AMQProtocolSession getProtocolSession()
- {
- return _protocolSession;
- }
-
- public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException
- {
- AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
- writeMessageDelivery(entry, channelId, deliverBody);
- }
-
-
- 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, org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl.CLASS_ID);
- chb.bodySize = message.getSize();
- return chb;
- }
- }
-
-
- 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
- {
-
-
- int bodySize = (int) message.getSize();
-
- if(bodySize == 0)
- {
- SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
- contentHeaderBody);
-
- writeFrame(compositeBlock);
- }
- else
- {
- int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
-
-
- int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
-
- int writtenSize = capacity;
-
- AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);
-
- CompositeAMQBodyBlock
- compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
- writeFrame(compositeBlock);
-
- while(writtenSize < bodySize)
- {
- capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
- MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);
- writtenSize += capacity;
-
- writeFrame(new AMQFrame(channelId, body));
- }
- }
- }
-
- private class MessageContentSourceBody implements AMQBody
- {
- public static final byte TYPE = 3;
- private int _length;
- private MessageContentSource _message;
- private int _offset;
-
- public MessageContentSourceBody(MessageContentSource message, int offset, int length)
- {
- _message = message;
- _offset = offset;
- _length = length;
- }
-
- public byte getFrameType()
- {
- return TYPE;
- }
-
- public int getSize()
- {
- return _length;
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- byte[] data = new byte[_length];
-
- _message.getContent(java.nio.ByteBuffer.wrap(data), _offset);
-
- buffer.write(data);
- }
-
- public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
- {
- throw new UnsupportedOperationException();
- }
- }
-
- private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
- {
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- contentHeaderBody);
- return contentHeader;
- }
-
-
- public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
- {
- AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
- writeMessageDelivery(entry, channelId, deliver);
- }
-
-
- private AMQBody createEncodedDeliverBody(QueueEntry entry,
- final long deliveryTag,
- final AMQShortString consumerTag)
- throws AMQException
- {
-
- final AMQShortString exchangeName;
- final AMQShortString routingKey;
-
- if(entry.getMessage() instanceof AMQMessage)
- {
- final AMQMessage message = (AMQMessage) entry.getMessage();
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- exchangeName = pb.getExchange();
- routingKey = pb.getRoutingKey();
- }
- else
- {
- MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
- DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
- exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
- routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
- }
-
- final boolean isRedelivered = entry.isRedelivered();
-
- final AMQBody returnBlock = new AMQBody()
- {
-
- public AMQBody _underlyingBody;
-
- public AMQBody createAMQBody()
- {
- return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
- deliveryTag,
- isRedelivered,
- exchangeName,
- routingKey);
-
-
-
-
-
- }
-
- public byte getFrameType()
- {
- return AMQMethodBody.TYPE;
- }
-
- public int getSize()
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- return _underlyingBody.getSize();
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- _underlyingBody.writePayload(buffer);
- }
-
- public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
- throws AMQException
- {
- throw new AMQException("This block should never be dispatched!");
- }
- };
- return returnBlock;
- }
-
- private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
- throws AMQException
- {
- final AMQShortString exchangeName;
- final AMQShortString routingKey;
-
- if(entry.getMessage() instanceof AMQMessage)
- {
- final AMQMessage message = (AMQMessage) entry.getMessage();
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- exchangeName = pb.getExchange();
- routingKey = pb.getRoutingKey();
- }
- else
- {
- MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
- DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
- exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
- routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
- }
-
- final boolean isRedelivered = entry.isRedelivered();
-
- BasicGetOkBody getOkBody =
- METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
- isRedelivered,
- exchangeName,
- routingKey,
- queueSize);
-
- return getOkBody;
- }
-
- public byte getProtocolMinorVersion()
- {
- return getProtocolSession().getProtocolMinorVersion();
- }
-
- public byte getProtocolMajorVersion()
- {
- return getProtocolSession().getProtocolMajorVersion();
- }
-
- private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
- int replyCode,
- AMQShortString replyText) throws AMQException
- {
-
- BasicReturnBody basicReturnBody =
- METHOD_REGISTRY.createBasicReturnBody(replyCode,
- replyText,
- messagePublishInfo.getExchange(),
- messagePublishInfo.getRoutingKey());
-
-
- return basicReturnBody;
- }
-
- public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
- throws AMQException
- {
-
- AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
-
- writeMessageDelivery(message, header, channelId, returnFrame);
- }
-
-
- public void writeFrame(AMQDataBlock block)
- {
- getProtocolSession().writeFrame(block);
- }
-
-
- public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
- {
-
- BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
- writeFrame(basicCancelOkBody.generateFrame(channelId));
-
- }
-
-
- public static final class CompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final AMQBody _contentBody;
- private final int _channel;
-
-
- public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
- _contentBody = contentBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
- }
- }
-
- public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final int _channel;
-
-
- public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
- }
- }
-}
+/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +/* + * This file is auto-generated by Qpid Gentools v.0.1 - do not modify. + * Supported AMQP versions: + * 8-0 + */ +package org.apache.qpid.server.output.amqp0_8; + +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; +import org.apache.qpid.server.protocol.AMQProtocolSession; +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.MessagePublishInfo; +import org.apache.qpid.AMQException; +import org.apache.qpid.transport.DeliveryProperties; + +import java.io.DataOutput; +import java.io.IOException; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0); + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag); + writeMessageDelivery(entry, channelId, deliverBody); + } + + + 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, org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl.CLASS_ID); + chb.bodySize = message.getSize(); + return chb; + } + } + + + 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 + { + + + int bodySize = (int) message.getSize(); + + if(bodySize == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead(); + + + int capacity = bodySize > maxBodySize ? maxBodySize : bodySize; + + int writtenSize = capacity; + + AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity); + + CompositeAMQBodyBlock + compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + while(writtenSize < bodySize) + { + capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize; + MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity); + writtenSize += capacity; + + writeFrame(new AMQFrame(channelId, body)); + } + } + } + + private class MessageContentSourceBody implements AMQBody + { + public static final byte TYPE = 3; + private int _length; + private MessageContentSource _message; + private int _offset; + + public MessageContentSourceBody(MessageContentSource message, int offset, int length) + { + _message = message; + _offset = offset; + _length = length; + } + + public byte getFrameType() + { + return TYPE; + } + + public int getSize() + { + return _length; + } + + public void writePayload(DataOutput buffer) throws IOException + { + byte[] data = new byte[_length]; + + _message.getContent(java.nio.ByteBuffer.wrap(data), _offset); + + buffer.write(data); + } + + public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException + { + throw new UnsupportedOperationException(); + } + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException + { + AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize); + writeMessageDelivery(entry, channelId, deliver); + } + + + private AMQBody createEncodedDeliverBody(QueueEntry entry, + final long deliveryTag, + final AMQShortString consumerTag) + throws AMQException + { + + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().getDeliveryProperties(); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + final AMQBody returnBlock = new AMQBody() + { + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + isRedelivered, + exchangeName, + routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(DataOutput buffer) throws IOException + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize) + throws AMQException + { + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().getDeliveryProperties(); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + isRedelivered, + exchangeName, + routingKey, + queueSize); + + return getOkBody; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, + int replyCode, + AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + messagePublishInfo.getExchange(), + messagePublishInfo.getRoutingKey()); + + + return basicReturnBody; + } + + public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + + AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText); + + writeMessageDelivery(message, header, channelId, returnFrame); + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(DataOutput buffer) throws IOException + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(DataOutput buffer) throws IOException + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } +} 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 aef3483282..010afcb1a9 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,419 +1,418 @@ -package org.apache.qpid.server.output.amqp0_9;
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.output.HeaderPropertiesConverter;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-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.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;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
-{
- private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
-
-
- public static Factory getInstanceFactory()
- {
- return new Factory()
- {
-
- public ProtocolOutputConverter newInstance(AMQProtocolSession session)
- {
- return new ProtocolOutputConverterImpl(session);
- }
- };
- }
-
- private final AMQProtocolSession _protocolSession;
-
- private ProtocolOutputConverterImpl(AMQProtocolSession session)
- {
- _protocolSession = session;
- }
-
-
- public AMQProtocolSession getProtocolSession()
- {
- return _protocolSession;
- }
-
- public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException
- {
- AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
- writeMessageDelivery(entry, channelId, deliverBody);
- }
-
-
- 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;
- }
- }
-
-
- 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
- {
-
-
- int bodySize = (int) message.getSize();
-
- if(bodySize == 0)
- {
- SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
- contentHeaderBody);
-
- writeFrame(compositeBlock);
- }
- else
- {
- int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
-
-
- int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
-
- int writtenSize = capacity;
-
- AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);
-
-
- CompositeAMQBodyBlock
- compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
- writeFrame(compositeBlock);
-
- while(writtenSize < bodySize)
- {
- capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
- MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);
- writtenSize += capacity;
-
- writeFrame(new AMQFrame(channelId, body));
- }
- }
- }
-
- private class MessageContentSourceBody implements AMQBody
- {
- public static final byte TYPE = 3;
- private int _length;
- private MessageContentSource _message;
- private int _offset;
-
- public MessageContentSourceBody(MessageContentSource message, int offset, int length)
- {
- _message = message;
- _offset = offset;
- _length = length;
- }
-
- public byte getFrameType()
- {
- return TYPE;
- }
-
- public int getSize()
- {
- return _length;
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- byte[] data = new byte[_length];
-
- _message.getContent(ByteBuffer.wrap(data), _offset);
-
- buffer.write(data);
- }
-
- public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
- {
- throw new UnsupportedOperationException();
- }
- }
-
-
- private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
- {
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- contentHeaderBody);
- return contentHeader;
- }
-
-
- public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
- {
- AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
- writeMessageDelivery(entry, channelId, deliver);
- }
-
-
- private AMQBody createEncodedDeliverBody(QueueEntry entry,
- final long deliveryTag,
- final AMQShortString consumerTag)
- throws AMQException
- {
-
- final AMQShortString exchangeName;
- final AMQShortString routingKey;
-
- if(entry.getMessage() instanceof AMQMessage)
- {
- final AMQMessage message = (AMQMessage) entry.getMessage();
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- exchangeName = pb.getExchange();
- routingKey = pb.getRoutingKey();
- }
- else
- {
- MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
- DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
- exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
- routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
- }
-
- final boolean isRedelivered = entry.isRedelivered();
-
- final AMQBody returnBlock = new AMQBody()
- {
-
- public AMQBody _underlyingBody;
-
- public AMQBody createAMQBody()
- {
- return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
- deliveryTag,
- isRedelivered,
- exchangeName,
- routingKey);
-
-
-
-
-
- }
-
- public byte getFrameType()
- {
- return AMQMethodBody.TYPE;
- }
-
- public int getSize()
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- return _underlyingBody.getSize();
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- _underlyingBody.writePayload(buffer);
- }
-
- public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
- throws AMQException
- {
- throw new AMQException("This block should never be dispatched!");
- }
- };
- return returnBlock;
- }
-
- private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
- throws AMQException
- {
- final AMQShortString exchangeName;
- final AMQShortString routingKey;
-
- if(entry.getMessage() instanceof AMQMessage)
- {
- final AMQMessage message = (AMQMessage) entry.getMessage();
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- exchangeName = pb.getExchange();
- routingKey = pb.getRoutingKey();
- }
- else
- {
- MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
- DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
- exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
- routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
- }
-
- final boolean isRedelivered = entry.isRedelivered();
-
- BasicGetOkBody getOkBody =
- METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
- isRedelivered,
- exchangeName,
- routingKey,
- queueSize);
-
- return getOkBody;
- }
-
- public byte getProtocolMinorVersion()
- {
- return getProtocolSession().getProtocolMinorVersion();
- }
-
- public byte getProtocolMajorVersion()
- {
- return getProtocolSession().getProtocolMajorVersion();
- }
-
- private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
- int replyCode,
- AMQShortString replyText) throws AMQException
- {
-
- BasicReturnBody basicReturnBody =
- METHOD_REGISTRY.createBasicReturnBody(replyCode,
- replyText,
- messagePublishInfo.getExchange(),
- messagePublishInfo.getRoutingKey());
-
-
- return basicReturnBody;
- }
-
- public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
- throws AMQException
- {
-
- AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
-
- writeMessageDelivery(message, header, channelId, returnFrame);
- }
-
-
- public void writeFrame(AMQDataBlock block)
- {
- getProtocolSession().writeFrame(block);
- }
-
-
- public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
- {
-
- BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
- writeFrame(basicCancelOkBody.generateFrame(channelId));
-
- }
-
-
- public static final class CompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final AMQBody _contentBody;
- private final int _channel;
-
-
- public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
- _contentBody = contentBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
- }
- }
-
- public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final int _channel;
-
-
- public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
- }
- }
-
-}
+package org.apache.qpid.server.output.amqp0_9; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.HeaderPropertiesConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +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.amqp_0_9.BasicGetBodyImpl; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; + +import java.io.DataOutput; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9); + + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag); + writeMessageDelivery(entry, channelId, deliverBody); + } + + + 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; + } + } + + + 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 + { + + + int bodySize = (int) message.getSize(); + + if(bodySize == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead(); + + + int capacity = bodySize > maxBodySize ? maxBodySize : bodySize; + + int writtenSize = capacity; + + AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity); + + + CompositeAMQBodyBlock + compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + while(writtenSize < bodySize) + { + capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize; + MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity); + writtenSize += capacity; + + writeFrame(new AMQFrame(channelId, body)); + } + } + } + + private class MessageContentSourceBody implements AMQBody + { + public static final byte TYPE = 3; + private int _length; + private MessageContentSource _message; + private int _offset; + + public MessageContentSourceBody(MessageContentSource message, int offset, int length) + { + _message = message; + _offset = offset; + _length = length; + } + + public byte getFrameType() + { + return TYPE; + } + + public int getSize() + { + return _length; + } + + public void writePayload(DataOutput buffer) throws IOException + { + byte[] data = new byte[_length]; + + _message.getContent(ByteBuffer.wrap(data), _offset); + + buffer.write(data); + } + + public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException + { + throw new UnsupportedOperationException(); + } + } + + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException + { + AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize); + writeMessageDelivery(entry, channelId, deliver); + } + + + private AMQBody createEncodedDeliverBody(QueueEntry entry, + final long deliveryTag, + final AMQShortString consumerTag) + throws AMQException + { + + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().getDeliveryProperties(); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + final AMQBody returnBlock = new AMQBody() + { + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + isRedelivered, + exchangeName, + routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(DataOutput buffer) throws IOException + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize) + throws AMQException + { + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().getDeliveryProperties(); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + isRedelivered, + exchangeName, + routingKey, + queueSize); + + return getOkBody; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, + int replyCode, + AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + messagePublishInfo.getExchange(), + messagePublishInfo.getRoutingKey()); + + + return basicReturnBody; + } + + public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + + AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText); + + writeMessageDelivery(message, header, channelId, returnFrame); + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(DataOutput buffer) throws IOException + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(DataOutput buffer) throws IOException + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java index 10748298bc..5e2b3e4556 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java @@ -1,414 +1,425 @@ -package org.apache.qpid.server.output.amqp0_9_1;
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-import org.apache.qpid.server.output.ProtocolOutputConverter;
-import org.apache.qpid.server.output.HeaderPropertiesConverter;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-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.amqp_0_91.BasicGetBodyImpl;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
-{
- private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_91);
-
- public static Factory getInstanceFactory()
- {
- return new Factory()
- {
-
- public ProtocolOutputConverter newInstance(AMQProtocolSession session)
- {
- return new ProtocolOutputConverterImpl(session);
- }
- };
- }
-
- private final AMQProtocolSession _protocolSession;
-
- private ProtocolOutputConverterImpl(AMQProtocolSession session)
- {
- _protocolSession = session;
- }
-
-
- public AMQProtocolSession getProtocolSession()
- {
- return _protocolSession;
- }
-
- public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
- throws AMQException
- {
- AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
- writeMessageDelivery(entry, channelId, deliverBody);
- }
-
-
- 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;
- }
- }
-
-
- 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
- {
-
-
- int bodySize = (int) message.getSize();
-
- if(bodySize == 0)
- {
- SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
- contentHeaderBody);
-
- writeFrame(compositeBlock);
- }
- else
- {
- int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
-
-
- int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
-
- int writtenSize = capacity;
-
- AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);
-
- CompositeAMQBodyBlock
- compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
- writeFrame(compositeBlock);
-
- while(writtenSize < bodySize)
- {
- capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
- MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);
- writtenSize += capacity;
-
- writeFrame(new AMQFrame(channelId, body));
- }
- }
- }
-
- private class MessageContentSourceBody implements AMQBody
- {
- public static final byte TYPE = 3;
- private int _length;
- private MessageContentSource _message;
- private int _offset;
-
- public MessageContentSourceBody(MessageContentSource message, int offset, int length)
- {
- _message = message;
- _offset = offset;
- _length = length;
- }
-
- public byte getFrameType()
- {
- return TYPE;
- }
-
- public int getSize()
- {
- return _length;
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- byte[] data = new byte[_length];
-
- _message.getContent(java.nio.ByteBuffer.wrap(data), _offset);
-
- buffer.write(data);
- }
-
- public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
- {
- throw new UnsupportedOperationException();
- }
- }
-
- private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
- {
-
- AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
- contentHeaderBody);
- return contentHeader;
- }
-
-
- public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
- {
- AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
- writeMessageDelivery(entry, channelId, deliver);
- }
-
-
- private AMQBody createEncodedDeliverBody(QueueEntry entry,
- final long deliveryTag,
- final AMQShortString consumerTag)
- throws AMQException
- {
-
- final AMQShortString exchangeName;
- final AMQShortString routingKey;
-
- if(entry.getMessage() instanceof AMQMessage)
- {
- final AMQMessage message = (AMQMessage) entry.getMessage();
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- exchangeName = pb.getExchange();
- routingKey = pb.getRoutingKey();
- }
- else
- {
- MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
- DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
- exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
- routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
- }
-
- final boolean isRedelivered = entry.isRedelivered();
-
- final AMQBody returnBlock = new AMQBody()
- {
-
- public AMQBody _underlyingBody;
-
- public AMQBody createAMQBody()
- {
- return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
- deliveryTag,
- isRedelivered,
- exchangeName,
- routingKey);
-
-
-
-
-
- }
-
- public byte getFrameType()
- {
- return AMQMethodBody.TYPE;
- }
-
- public int getSize()
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- return _underlyingBody.getSize();
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- if(_underlyingBody == null)
- {
- _underlyingBody = createAMQBody();
- }
- _underlyingBody.writePayload(buffer);
- }
-
- public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
- throws AMQException
- {
- throw new AMQException("This block should never be dispatched!");
- }
- };
- return returnBlock;
- }
-
- private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
- throws AMQException
- {
- final AMQShortString exchangeName;
- final AMQShortString routingKey;
-
- if(entry.getMessage() instanceof AMQMessage)
- {
- final AMQMessage message = (AMQMessage) entry.getMessage();
- final MessagePublishInfo pb = message.getMessagePublishInfo();
- exchangeName = pb.getExchange();
- routingKey = pb.getRoutingKey();
- }
- else
- {
- MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
- DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);
- exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
- routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
- }
-
- final boolean isRedelivered = entry.isRedelivered();
-
- BasicGetOkBody getOkBody =
- METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
- isRedelivered,
- exchangeName,
- routingKey,
- queueSize);
-
- return getOkBody;
- }
-
- public byte getProtocolMinorVersion()
- {
- return getProtocolSession().getProtocolMinorVersion();
- }
-
- public byte getProtocolMajorVersion()
- {
- return getProtocolSession().getProtocolMajorVersion();
- }
-
- private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
- int replyCode,
- AMQShortString replyText) throws AMQException
- {
-
- BasicReturnBody basicReturnBody =
- METHOD_REGISTRY.createBasicReturnBody(replyCode,
- replyText,
- messagePublishInfo.getExchange(),
- messagePublishInfo.getRoutingKey());
-
-
- return basicReturnBody;
- }
-
- public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
- throws AMQException
- {
-
- AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
-
- writeMessageDelivery(message, header, channelId, returnFrame);
- }
-
-
- public void writeFrame(AMQDataBlock block)
- {
- getProtocolSession().writeFrame(block);
- }
-
-
- public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
- {
-
- BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
- writeFrame(basicCancelOkBody.generateFrame(channelId));
-
- }
-
-
- public static final class CompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final AMQBody _contentBody;
- private final int _channel;
-
-
- public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
- _contentBody = contentBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
- }
- }
-
- public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
- {
- public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
-
- private final AMQBody _methodBody;
- private final AMQBody _headerBody;
- private final int _channel;
-
-
- public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
- {
- _channel = channel;
- _methodBody = methodBody;
- _headerBody = headerBody;
-
- }
-
- public long getSize()
- {
- return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
- }
-
- public void writePayload(DataOutputStream buffer) throws IOException
- {
- AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
- }
- }
-
+package org.apache.qpid.server.output.amqp0_9_1; +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +import org.apache.qpid.server.output.ProtocolOutputConverter; +import org.apache.qpid.server.output.HeaderPropertiesConverter; +import org.apache.qpid.server.protocol.AMQProtocolSession; +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.amqp_0_91.BasicGetBodyImpl; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.AMQException; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; + +import java.io.DataOutput; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class ProtocolOutputConverterImpl implements ProtocolOutputConverter +{ + private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_91); + + public static Factory getInstanceFactory() + { + return new Factory() + { + + public ProtocolOutputConverter newInstance(AMQProtocolSession session) + { + return new ProtocolOutputConverterImpl(session); + } + }; + } + + private final AMQProtocolSession _protocolSession; + + private ProtocolOutputConverterImpl(AMQProtocolSession session) + { + _protocolSession = session; + } + + + public AMQProtocolSession getProtocolSession() + { + return _protocolSession; + } + + public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag) + throws AMQException + { + AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag); + writeMessageDelivery(entry, channelId, deliverBody); + } + + + 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; + } + } + + + 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 + { + + + int bodySize = (int) message.getSize(); + + if(bodySize == 0) + { + SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, + contentHeaderBody); + + writeFrame(compositeBlock); + } + else + { + int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead(); + + + int capacity = bodySize > maxBodySize ? maxBodySize : bodySize; + + int writtenSize = capacity; + + AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity); + + CompositeAMQBodyBlock + compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + writeFrame(compositeBlock); + + while(writtenSize < bodySize) + { + capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize; + MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity); + writtenSize += capacity; + + writeFrame(new AMQFrame(channelId, body)); + } + } + } + + private class MessageContentSourceBody implements AMQBody + { + public static final byte TYPE = 3; + private int _length; + private MessageContentSource _message; + private int _offset; + + public MessageContentSourceBody(MessageContentSource message, int offset, int length) + { + _message = message; + _offset = offset; + _length = length; + } + + public byte getFrameType() + { + return TYPE; + } + + public int getSize() + { + return _length; + } + + public void writePayload(DataOutput buffer) throws IOException + { + ByteBuffer buf = _message.getContent(_offset, _length); + + if(buf.hasArray()) + { + buffer.write(buf.array(), buf.arrayOffset()+buf.position(), buf.remaining()); + } + else + { + + byte[] data = new byte[_length]; + + buf.get(data); + + buffer.write(data); + } + } + + public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException + { + throw new UnsupportedOperationException(); + } + } + + private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody) + { + + AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId, + contentHeaderBody); + return contentHeader; + } + + + public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException + { + AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize); + writeMessageDelivery(entry, channelId, deliver); + } + + + private AMQBody createEncodedDeliverBody(QueueEntry entry, + final long deliveryTag, + final AMQShortString consumerTag) + throws AMQException + { + + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().getDeliveryProperties(); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + final AMQBody returnBlock = new AMQBody() + { + + public AMQBody _underlyingBody; + + public AMQBody createAMQBody() + { + return METHOD_REGISTRY.createBasicDeliverBody(consumerTag, + deliveryTag, + isRedelivered, + exchangeName, + routingKey); + + + + + + } + + public byte getFrameType() + { + return AMQMethodBody.TYPE; + } + + public int getSize() + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + return _underlyingBody.getSize(); + } + + public void writePayload(DataOutput buffer) throws IOException + { + if(_underlyingBody == null) + { + _underlyingBody = createAMQBody(); + } + _underlyingBody.writePayload(buffer); + } + + public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) + throws AMQException + { + throw new AMQException("This block should never be dispatched!"); + } + }; + return returnBlock; + } + + private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize) + throws AMQException + { + final AMQShortString exchangeName; + final AMQShortString routingKey; + + if(entry.getMessage() instanceof AMQMessage) + { + final AMQMessage message = (AMQMessage) entry.getMessage(); + final MessagePublishInfo pb = message.getMessagePublishInfo(); + exchangeName = pb.getExchange(); + routingKey = pb.getRoutingKey(); + } + else + { + MessageTransferMessage message = (MessageTransferMessage) entry.getMessage(); + DeliveryProperties delvProps = message.getHeader().getDeliveryProperties(); + exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange()); + routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey()); + } + + final boolean isRedelivered = entry.isRedelivered(); + + BasicGetOkBody getOkBody = + METHOD_REGISTRY.createBasicGetOkBody(deliveryTag, + isRedelivered, + exchangeName, + routingKey, + queueSize); + + return getOkBody; + } + + public byte getProtocolMinorVersion() + { + return getProtocolSession().getProtocolMinorVersion(); + } + + public byte getProtocolMajorVersion() + { + return getProtocolSession().getProtocolMajorVersion(); + } + + private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo, + int replyCode, + AMQShortString replyText) throws AMQException + { + + BasicReturnBody basicReturnBody = + METHOD_REGISTRY.createBasicReturnBody(replyCode, + replyText, + messagePublishInfo.getExchange(), + messagePublishInfo.getRoutingKey()); + + + return basicReturnBody; + } + + public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText) + throws AMQException + { + + AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText); + + writeMessageDelivery(message, header, channelId, returnFrame); + } + + + public void writeFrame(AMQDataBlock block) + { + getProtocolSession().writeFrame(block); + } + + + public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag) + { + + BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag); + writeFrame(basicCancelOkBody.generateFrame(channelId)); + + } + + + public static final class CompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final AMQBody _contentBody; + private final int _channel; + + + public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + _contentBody = contentBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize(); + } + + public void writePayload(DataOutput buffer) throws IOException + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody); + } + } + + public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock + { + public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead(); + + private final AMQBody _methodBody; + private final AMQBody _headerBody; + private final int _channel; + + + public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody) + { + _channel = channel; + _methodBody = methodBody; + _headerBody = headerBody; + + } + + public long getSize() + { + return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ; + } + + public void writePayload(DataOutput buffer) throws IOException + { + AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody); + } + } + }
\ No newline at end of file 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 4e5088808a..241ab3fcb9 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 @@ -93,6 +93,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr // to save boxing the channelId and looking up in a map... cache in an array the low numbered // channels. This value must be of the form 2^x - 1. private static final int CHANNEL_CACHE_SIZE = 0xff; + private static final int REUSABLE_BYTE_BUFFER_CAPACITY = 65 * 1024; private AMQShortString _contextKey; @@ -262,6 +263,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr closeProtocolSession(); } } + receiveComplete(); } catch (Exception e) { @@ -270,6 +272,15 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr } } + private void receiveComplete() + { + for (AMQChannel channel : _channelMap.values()) + { + channel.receivedComplete(); + } + + } + public void dataBlockReceived(AMQDataBlock message) throws Exception { _lastReceived = message; @@ -387,35 +398,51 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr } } + + private final byte[] _reusableBytes = new byte[REUSABLE_BYTE_BUFFER_CAPACITY]; + private final ByteBuffer _reusableByteBuffer = ByteBuffer.wrap(_reusableBytes); + private final BytesDataOutput _reusableDataOutput = new BytesDataOutput(_reusableBytes); + private ByteBuffer asByteBuffer(AMQDataBlock block) { - final ByteBuffer buf = ByteBuffer.allocate((int) block.getSize()); + final int size = (int) block.getSize(); - try - { - block.writePayload(new DataOutputStream(new OutputStream() - { + final byte[] data; - @Override - public void write(int b) throws IOException - { - buf.put((byte) b); - } + if(size > REUSABLE_BYTE_BUFFER_CAPACITY) + { + data= new byte[size]; + } + else + { - @Override - public void write(byte[] b, int off, int len) throws IOException - { - buf.put(b, off, len); - } - })); + data = _reusableBytes; + } + _reusableDataOutput.setBuffer(data); + + try + { + block.writePayload(_reusableDataOutput); } catch (IOException e) { throw new RuntimeException(e); } - buf.flip(); + final ByteBuffer buf; + + if(size <= REUSABLE_BYTE_BUFFER_CAPACITY) + { + buf = _reusableByteBuffer; + buf.position(0); + } + else + { + buf = ByteBuffer.wrap(data); + } + buf.limit(_reusableDataOutput.length()); + return buf; } @@ -1418,8 +1445,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr _deferFlush = deferFlush; } - - public String getUserName() { return getAuthorizedPrincipal().getName(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java index bc63403a86..c55fe321fc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.protocol; import org.apache.qpid.AMQException; import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.SimpleAMQQueue; public interface AMQSessionModel { @@ -51,4 +53,8 @@ public interface AMQSessionModel * @param idleClose time in milliseconds before closing connection with idle transaction */ public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException; + + void block(AMQQueue queue); + + void unblock(AMQQueue queue); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java index 3faf896aae..42b49cb546 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java @@ -20,17 +20,14 @@ */ package org.apache.qpid.server.protocol.v1_0; +import java.util.List; +import org.apache.qpid.AMQException; import org.apache.qpid.amqp_1_0.type.Outcome; import org.apache.qpid.amqp_1_0.type.messaging.Accepted; - -import org.apache.qpid.AMQException; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.txn.ServerTransaction; -import java.util.ArrayList; -import java.util.Arrays; - public class ExchangeDestination implements ReceivingDestination, SendingDestination { private static final Accepted ACCEPTED = new Accepted(); @@ -50,7 +47,7 @@ public class ExchangeDestination implements ReceivingDestination, SendingDestina public Outcome send(final Message_1_0 message, ServerTransaction txn) { - final ArrayList<? extends BaseQueue> queues = _exchange.route(message); + final List<? extends BaseQueue> queues = _exchange.route(message); txn.enqueue(queues,message, new ServerTransaction.Action() { @@ -77,7 +74,7 @@ public class ExchangeDestination implements ReceivingDestination, SendingDestina { // NO-OP } - }); + }, System.currentTimeMillis()); return ACCEPTED; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java index 5082d7097a..140a815f57 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java @@ -21,20 +21,18 @@ package org.apache.qpid.server.protocol.v1_0; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.util.List; +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.SessionConfig; -import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.message.MessageMetaData_1_0; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.store.StoredMessage; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; -import java.util.Collection; -import java.util.List; - -public class Message_1_0 implements ServerMessage<Message_1_0>, InboundMessage +public class Message_1_0 implements ServerMessage, InboundMessage { private final StoredMessage<MessageMetaData_1_0> _storedMessage; private List<ByteBuffer> _fragments; @@ -63,6 +61,11 @@ public class Message_1_0 implements ServerMessage<Message_1_0>, InboundMessage } } + public AMQShortString getRoutingKeyShortString() + { + return AMQShortString.valueOf(getRoutingKey()); + } + private MessageMetaData_1_0 getMessageMetaData() { return _storedMessage.getMetaData(); @@ -73,6 +76,11 @@ public class Message_1_0 implements ServerMessage<Message_1_0>, InboundMessage return getMessageMetaData().getMessageHeader(); } + public StoredMessage getStoredMessage() + { + return _storedMessage; + } + public boolean isPersistent() { return getMessageMetaData().isPersistent(); @@ -105,7 +113,7 @@ public class Message_1_0 implements ServerMessage<Message_1_0>, InboundMessage return new Reference(this); } - public Long getMessageNumber() + public long getMessageNumber() { return _storedMessage.getMessageNumber(); } @@ -120,6 +128,14 @@ public class Message_1_0 implements ServerMessage<Message_1_0>, InboundMessage return _storedMessage.getContent(offset, buf); } + public ByteBuffer getContent(int offset, int size) + { + ByteBuffer buf = ByteBuffer.allocate(size); + buf.limit(getContent(buf, offset)); + + return buf; + } + public SessionConfig getSessionConfig() { return null; //TODO diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java index 5c0143d809..c994ac9a2a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java @@ -20,6 +20,12 @@ */ package org.apache.qpid.server.protocol.v1_0; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.qpid.amqp_1_0.messaging.SectionDecoderImpl; import org.apache.qpid.amqp_1_0.transport.DeliveryStateHandler; import org.apache.qpid.amqp_1_0.transport.LinkEndpoint; @@ -35,17 +41,12 @@ import org.apache.qpid.amqp_1_0.type.transaction.TransactionalState; import org.apache.qpid.amqp_1_0.type.transport.Detach; import org.apache.qpid.amqp_1_0.type.transport.ReceiverSettleMode; import org.apache.qpid.amqp_1_0.type.transport.Transfer; - import org.apache.qpid.server.message.MessageMetaData_1_0; import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.txn.AutoCommitTransaction; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; -import java.util.*; - public class ReceivingLink_1_0 implements ReceivingLinkListener, Link_1_0, DeliveryStateHandler { private VirtualHost _vhost; @@ -181,7 +182,7 @@ public class ReceivingLink_1_0 implements ReceivingLinkListener, Link_1_0, Deliv else { Session_1_0 session = getSession(); - transaction = session != null ? session.getTransaction(null) : new AutoCommitTransaction(_vhost.getTransactionLog()); + transaction = session != null ? session.getTransaction(null) : new AutoCommitTransaction(_vhost.getMessageStore()); } Outcome outcome = _destination.send(message, transaction); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java index 1b335cf964..ed9d58994a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java @@ -439,7 +439,7 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS if(outcome instanceof Accepted) { - AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getTransactionLog()); + AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getMessageStore()); if(_subscription.acquires()) { txn.dequeue(Collections.singleton(queueEntry), @@ -459,7 +459,7 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS } else if(outcome instanceof Released) { - AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getTransactionLog()); + AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getMessageStore()); if(_subscription.acquires()) { txn.dequeue(Collections.singleton(queueEntry), diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java index 0e700dc10b..a05d14816a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java @@ -124,7 +124,7 @@ public class TxnCoordinatorLink_1_0 implements ReceivingLinkListener, Link_1_0 } txnId = Integer.valueOf(txnId.intValue() + 1); - _openTransactions.put(txnId, new LocalTransaction(_vhost.getTransactionLog())); + _openTransactions.put(txnId, new LocalTransaction(_vhost.getMessageStore())); Declared state = new Declared(); 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 6dfdc5e8b4..32d9c4878a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -149,7 +149,13 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void removeMessagesFromQueue(long fromMessageId, long toMessageId); - + static interface Visitor + { + boolean visit(QueueEntry entry); + } + + void visit(Visitor visitor); + long getMaximumMessageSize(); @@ -217,7 +223,7 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer Map<String, Object> getArguments(); - void checkCapacity(AMQChannel channel); + void checkCapacity(AMQSessionModel channel); /** * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index b4765d6227..143a6ae8ca 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 @@ -557,7 +557,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que List<String> list = new ArrayList<String>(); AMQMessageHeader header = msg.getMessageHeader(); - MessageProperties msgProps = msg.getHeader().get(MessageProperties.class); + MessageProperties msgProps = msg.getHeader().getMessageProperties(); String appID = null; String userID = null; @@ -619,7 +619,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog()); + ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getMessageStore()); _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn); txn.commit(); } @@ -654,7 +654,7 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); } - ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog()); + ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getMessageStore()); _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java index 05e0efd9a6..0bd40e8f13 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java @@ -35,6 +35,7 @@ public interface BaseQueue extends TransactionLogResource void enqueue(ServerMessage message) throws AMQException; void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException; + void enqueue(ServerMessage message, boolean transactional, PostEnqueueAction action) throws AMQException; boolean isDurable(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java index c4762c98c9..ab0a567114 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java @@ -100,7 +100,7 @@ public class ConflationQueueList extends SimpleQueueEntryList { if(entry.acquire()) { - ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getMessageStore()); txn.dequeue(entry.getQueue(),entry.getMessage(), new ServerTransaction.Action() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java index 26112d9f53..31e9725e47 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.framing.AMQShortString; public class InboundMessageAdapter implements InboundMessage { @@ -44,6 +45,11 @@ public class InboundMessageAdapter implements InboundMessage } + public AMQShortString getRoutingKeyShortString() + { + return AMQShortString.valueOf(_entry.getMessage()); + } + public String getRoutingKey() { return _entry.getMessage().getRoutingKey(); 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 a56f5685b8..19a7a15ad1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java @@ -63,7 +63,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes * delivered. It is <b>cleared after delivery has been attempted</b>. Any persistent record of destinations is done * by the message handle. */ - private ArrayList<? extends BaseQueue> _destinationQueues; + private List<? extends BaseQueue> _destinationQueues; private long _expiration; @@ -126,12 +126,18 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes public MessageMetaData headersReceived() { - _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0); + + return headersReceived(System.currentTimeMillis()); + } + + public MessageMetaData headersReceived(long currentTime) + { + _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0, currentTime); return _messageMetaData; } - public ArrayList<? extends BaseQueue> getDestinationQueues() + public List<? extends BaseQueue> getDestinationQueues() { return _destinationQueues; } @@ -158,6 +164,11 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes return _messagePublishInfo.getExchange(); } + public AMQShortString getRoutingKeyShortString() + { + return _messagePublishInfo.getRoutingKey(); + } + public String getRoutingKey() { return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString(); @@ -209,7 +220,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes return getContentHeader().bodySize; } - public Long getMessageNumber() + public long getMessageNumber() { return _storedMessageHandle.getMessageNumber(); } @@ -225,7 +236,7 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes } - public void enqueue(final ArrayList<? extends BaseQueue> queues) + public void enqueue(final List<? extends BaseQueue> queues) { _destinationQueues = queues; } @@ -288,6 +299,15 @@ public class IncomingMessage implements Filterable, InboundMessage, EnqueableMes } + + public ByteBuffer getContent(int offset, int size) + { + ByteBuffer buf = ByteBuffer.allocate(size); + getContent(buf,offset); + buf.flip(); + return buf; + } + public void setStoredMessage(StoredMessage<MessageMetaData> storedMessageHandle) { _storedMessageHandle = storedMessageHandle; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java index b16d1eb8e3..0220a553a7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java @@ -1,12 +1,14 @@ package org.apache.qpid.server.queue; import java.util.Map; + import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.virtualhost.VirtualHost; public abstract class OutOfOrderQueue extends SimpleAMQQueue { + protected OutOfOrderQueue(String name, boolean durable, String owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, QueueEntryListFactory entryListFactory, Map<String, Object> arguments) @@ -27,11 +29,8 @@ public abstract class OutOfOrderQueue extends SimpleAMQQueue QueueContext context = (QueueContext) subscription.getQueueContext(); if(context != null) { - QueueEntry subnode = context._lastSeenEntry; QueueEntry released = context._releasedEntry; - - while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired() - && (released == null || released.compareTo(entry) > 0)) + while(!entry.isAcquired() && (released == null || released.compareTo(entry) > 0)) { if(QueueContext._releasedUpdater.compareAndSet(context,released,entry)) { @@ -39,14 +38,11 @@ public abstract class OutOfOrderQueue extends SimpleAMQQueue } else { - subnode = context._lastSeenEntry; released = context._releasedEntry; } - } } } - } } 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 37fad54c07..142cfddb39 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 @@ -75,6 +75,11 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return State.AVAILABLE; } + + public String toString() + { + return getState().name(); + } } @@ -85,6 +90,11 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return State.DEQUEUED; } + + public String toString() + { + return getState().name(); + } } @@ -95,6 +105,11 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return State.DELETED; } + + public String toString() + { + return getState().name(); + } } public final class ExpiredState extends EntryState @@ -104,6 +119,11 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return State.EXPIRED; } + + public String toString() + { + return getState().name(); + } } @@ -113,6 +133,11 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return State.ACQUIRED; } + + public String toString() + { + return getState().name(); + } } public final class SubscriptionAcquiredState extends EntryState @@ -134,6 +159,11 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return _subscription; } + + public String toString() + { + return "{" + getState().name() + " : " + _subscription +"}"; + } } public final class SubscriptionAssignedState extends EntryState @@ -155,6 +185,12 @@ public interface QueueEntry extends Comparable<QueueEntry>, Filterable { return _subscription; } + + + public String toString() + { + return "{" + getState().name() + " : " + _subscription +"}"; + } } 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 f1e50427b1..82c6a2f127 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 @@ -35,6 +35,7 @@ import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.server.txn.ServerTransaction; public abstract class QueueEntryImpl implements QueueEntry @@ -420,7 +421,7 @@ public abstract class QueueEntryImpl implements QueueEntry if (rerouteQueues != null && rerouteQueues.size() != 0) { - ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); + ServerTransaction txn = new LocalTransaction(getQueue().getVirtualHost().getMessageStore()); txn.enqueue(rerouteQueues, message, new ServerTransaction.Action() { @@ -443,7 +444,8 @@ public abstract class QueueEntryImpl implements QueueEntry { } - }); + }, 0L); + txn.dequeue(currentQueue, message, new ServerTransaction.Action() { public void postCommit() @@ -456,8 +458,10 @@ public abstract class QueueEntryImpl implements QueueEntry } }); - } + + txn.commit(); } + } } public boolean isQueueDeleted() @@ -545,4 +549,11 @@ public abstract class QueueEntryImpl implements QueueEntry _deliveryCountUpdater.decrementAndGet(this); } + public String toString() + { + return "QueueEntryImpl{" + + "_entryId=" + _entryId + + ", _state=" + _state + + '}'; + } } 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 77c4b912e0..641aaa0a08 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 @@ -35,4 +35,6 @@ public interface QueueEntryList<Q extends QueueEntry> Q getHead(); void entryDeleted(Q queueEntry); + + int getPriorities(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java index 5270f9f740..0d44fe7cf3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java @@ -22,7 +22,6 @@ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.queue.QueueRunner; import org.apache.qpid.server.queue.SimpleAMQQueue; @@ -38,7 +37,7 @@ import java.util.concurrent.atomic.AtomicLong; * when straight-through delivery of a message to a subscription isn't * possible during the enqueue operation. */ -public class QueueRunner implements ReadWriteRunnable +public class QueueRunner implements Runnable { private static final Logger _logger = Logger.getLogger(QueueRunner.class); @@ -51,13 +50,11 @@ public class QueueRunner implements ReadWriteRunnable private final AtomicInteger _scheduled = new AtomicInteger(IDLE); - private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES; private final AtomicBoolean _stateChange = new AtomicBoolean(); private final AtomicLong _lastRunAgain = new AtomicLong(); private final AtomicLong _lastRunTime = new AtomicLong(); - private long _runs; private long _continues; public QueueRunner(SimpleAMQQueue queue) @@ -65,8 +62,6 @@ public class QueueRunner implements ReadWriteRunnable _queue = queue; } - private int trouble = 0; - public void run() { if(_scheduled.compareAndSet(SCHEDULED,RUNNING)) @@ -103,16 +98,6 @@ public class QueueRunner implements ReadWriteRunnable } } - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - public String toString() { return "QueueRunner-" + _queue.getLogActor(); 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 08dab4e5fc..4faca15eb0 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 @@ -18,22 +18,33 @@ */ package org.apache.qpid.server.queue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import javax.management.JMException; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.configuration.ConfigStore; import org.apache.qpid.server.configuration.ConfiguredObject; import org.apache.qpid.server.configuration.QueueConfigType; import org.apache.qpid.server.configuration.QueueConfiguration; import org.apache.qpid.server.configuration.SessionConfig; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.LogSubject; @@ -43,8 +54,12 @@ import org.apache.qpid.server.logging.messages.QueueMessages; import org.apache.qpid.server.logging.subjects.QueueLogSubject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.AuthorizationHolder; +import org.apache.qpid.server.subscription.AssignedSubscriptionMessageGroupManager; +import org.apache.qpid.server.subscription.DefinedGroupMessageGroupManager; +import org.apache.qpid.server.subscription.MessageGroupManager; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.subscription.SubscriptionList; import org.apache.qpid.server.txn.AutoCommitTransaction; @@ -52,27 +67,15 @@ import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; -import javax.management.JMException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener +public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, MessageGroupManager.SubscriptionResetHelper { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + private static final String QPID_GROUP_HEADER_KEY = "qpid.group_header_key"; + private static final String QPID_SHARED_MSG_GROUP = "qpid.shared_msg_group"; + private static final String QPID_DEFAULT_MESSAGE_GROUP = "qpid.default-message-group"; + private static final String QPID_NO_GROUP = "qpid.no-group"; + // TODO - should make this configurable at the vhost / broker level + private static final int DEFAULT_MAX_GROUPS = 255; private final VirtualHost _virtualHost; @@ -164,7 +167,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private AtomicInteger _deliveredMessages = new AtomicInteger(); private AtomicBoolean _stopped = new AtomicBoolean(false); - private final ConcurrentMap<AMQChannel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQChannel, Boolean>(); + private final ConcurrentMap<AMQSessionModel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQSessionModel, Boolean>(); private final AtomicBoolean _deleted = new AtomicBoolean(false); private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>(); @@ -190,6 +193,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener /** the maximum delivery count for each message on this queue or 0 if maximum delivery count is not to be enforced. */ private int _maximumDeliveryCount = ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount(); + private final MessageGroupManager _messageGroupManager; protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map<String,Object> arguments) { @@ -245,25 +249,15 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _logSubject = new QueueLogSubject(this); _logActor = new QueueActor(this, CurrentActor.get().getRootMessageLogger()); - // Log the correct creation message - - // Extract the number of priorities for this Queue. - // Leave it as 0 if we are a SimpleQueueEntryList - int priorities = 0; - if (entryListFactory instanceof PriorityQueueList.Factory) - { - priorities = ((PriorityQueueList)_entries).getPriorities(); - } - // Log the creation of this Queue. // The priorities display is toggled on if we set priorities > 0 CurrentActor.get().message(_logSubject, QueueMessages.CREATED(String.valueOf(_owner), - priorities, - _owner != null, - autoDelete, - durable, !durable, - priorities > 0)); + _entries.getPriorities(), + _owner != null, + autoDelete, + durable, !durable, + _entries.getPriorities() > 0)); getConfigStore().addConfiguredObject(this); @@ -277,6 +271,26 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _logger.error("AMQQueue MBean creation has failed ", e); } + if(arguments != null && arguments.containsKey(QPID_GROUP_HEADER_KEY)) + { + if(arguments.containsKey(QPID_SHARED_MSG_GROUP) && String.valueOf(arguments.get(QPID_SHARED_MSG_GROUP)).equals("1")) + { + String defaultGroup = String.valueOf(arguments.get(QPID_DEFAULT_MESSAGE_GROUP)); + _messageGroupManager = + new DefinedGroupMessageGroupManager(String.valueOf(arguments.get(QPID_GROUP_HEADER_KEY)), + defaultGroup == null ? QPID_NO_GROUP : defaultGroup, + this); + } + else + { + _messageGroupManager = new AssignedSubscriptionMessageGroupManager(String.valueOf(arguments.get(QPID_GROUP_HEADER_KEY)), DEFAULT_MAX_GROUPS); + } + } + else + { + _messageGroupManager = null; + } + resetNotifications(); } @@ -292,7 +306,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Getters and Setters - public void execute(ReadWriteRunnable runnable) + public void execute(Runnable runnable) { _asyncDelivery.execute(runnable); } @@ -491,6 +505,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener setExclusiveSubscriber(null); subscription.setQueueContext(null); + if(_messageGroupManager != null) + { + resetSubPointersForGroups(subscription, true); + } + // auto-delete queues must be deleted if there are no remaining subscribers if (_autoDelete && getDeleteOnNoConsumers() && !subscription.isTransient() && getConsumerCount() == 0 ) @@ -515,6 +534,34 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public void resetSubPointersForGroups(Subscription subscription, boolean clearAssignments) + { + QueueEntry entry = _messageGroupManager.findEarliestAssignedAvailableEntry(subscription); + if(clearAssignments) + { + _messageGroupManager.clearAssignments(subscription); + } + + if(entry != null) + { + SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator(); + // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards + while (subscriberIter.advance()) + { + Subscription sub = subscriberIter.getNode().getSubscription(); + + // we don't make browsers send the same stuff twice + if (sub.seesRequeues()) + { + updateSubRequeueEntry(sub, entry); + } + } + + deliverAsync(); + + } + } + public boolean getDeleteOnNoConsumers() { return _deleteOnNoConsumers; @@ -592,7 +639,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException { - incrementTxnEnqueueStats(message); + enqueue(message, false, action); + } + + public void enqueue(ServerMessage message, boolean transactional, PostEnqueueAction action) throws AMQException + { + + if(transactional) + { + incrementTxnEnqueueStats(message); + } incrementQueueCount(); incrementQueueSize(message); @@ -689,21 +745,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { try { - if (subscriptionReadyAndHasInterest(sub, entry) - && !sub.isSuspended()) + if (!sub.isSuspended() + && subscriptionReadyAndHasInterest(sub, entry) + && mightAssign(sub, entry) + && !sub.wouldSuspend(entry)) { - if (!sub.wouldSuspend(entry)) + if (sub.acquires() && !(assign(sub, entry) && 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); - } - else - { - deliverMessage(sub, entry, false); - } + // restore credit here that would have been taken away by wouldSuspend since we didn't manage + // to acquire the entry for this subscription + sub.restoreCredit(entry); + } + else + { + deliverMessage(sub, entry, false); } } } @@ -714,6 +769,20 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + private boolean assign(final Subscription sub, final QueueEntry entry) + { + return _messageGroupManager == null || _messageGroupManager.acceptMessage(sub, entry); + } + + + private boolean mightAssign(final Subscription sub, final QueueEntry entry) + { + if(_messageGroupManager == null || !sub.acquires()) + return true; + Subscription assigned = _messageGroupManager.getAssignedSubscription(entry); + return (assigned == null) || (assigned == sub); + } + protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry) { // This method is only required for queues which mess with ordering @@ -739,13 +808,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener private void incrementTxnEnqueueStats(final ServerMessage message) { - SessionConfig session = message.getSessionConfig(); - - if(session !=null && session.isTransactional()) - { - _msgTxnEnqueues.incrementAndGet(); - _byteTxnEnqueues.addAndGet(message.getSize()); - } + _msgTxnEnqueues.incrementAndGet(); + _byteTxnEnqueues.addAndGet(message.getSize()); } private void incrementTxnDequeueStats(QueueEntry entry) @@ -1057,6 +1121,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public boolean filterComplete(); } + + public List<QueueEntry> getMessagesOnTheQueue(final long fromMessageId, final long toMessageId) { return getMessagesOnTheQueue(new QueueEntryFilter() @@ -1111,6 +1177,24 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } + public void visit(final Visitor visitor) + { + QueueEntryIterator queueListIterator = _entries.iterator(); + + while(queueListIterator.advance()) + { + QueueEntry node = queueListIterator.getNode(); + + if(!node.isDispensed()) + { + if(visitor.visit(node)) + { + break; + } + } + } + } + /** * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue. * @@ -1487,7 +1571,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { } - }); + }, 0L); txn.dequeue(this, entry.getMessage(), new ServerTransaction.Action() { @@ -1565,7 +1649,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public void checkCapacity(AMQChannel channel) + public void checkCapacity(AMQSessionModel channel) { if(_capacity != 0l) { @@ -1575,10 +1659,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener //Overfull log message _logActor.message(_logSubject, QueueMessages.OVERFULL(_atomicQueueSize.get(), _capacity)); - if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null) - { - channel.block(this); - } + _blockedChannels.putIfAbsent(channel, Boolean.TRUE); + + channel.block(this); if(_atomicQueueSize.get() <= _flowResumeCapacity) { @@ -1610,7 +1693,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - for(AMQChannel c : _blockedChannels.keySet()) + for(AMQSessionModel c : _blockedChannels.keySet()) { c.unblock(this); _blockedChannels.remove(c); @@ -1752,11 +1835,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (node != null && node.isAvailable()) { - if (sub.hasInterest(node)) + if (sub.hasInterest(node) && mightAssign(sub, node)) { if (!sub.wouldSuspend(node)) { - if (sub.acquires() && !node.acquire(sub)) + if (sub.acquires() && !(assign(sub, node) && node.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 @@ -1813,7 +1896,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener QueueEntry node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen); boolean expired = false; - while (node != null && (!node.isAvailable() || (expired = node.expired()) || !sub.hasInterest(node))) + while (node != null && (!node.isAvailable() || (expired = node.expired()) || !sub.hasInterest(node) || + !mightAssign(sub,node))) { if (expired) { @@ -1841,6 +1925,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } + public boolean isEntryAheadOfSubscription(QueueEntry entry, Subscription sub) + { + QueueContext context = (QueueContext) sub.getQueueContext(); + if(context != null) + { + QueueEntry releasedNode = context._releasedEntry; + return releasedNode == null || releasedNode.compareTo(entry) < 0; + } + else + { + return false; + } + } /** * Used by queue Runners to asynchronously deliver messages to consumers. 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 0bb5dcc219..b40e5a28c2 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 @@ -185,6 +185,11 @@ public class SimpleQueueEntryList implements QueueEntryList<SimpleQueueEntryImpl advanceHead(); } + public int getPriorities() + { + return 0; + } + static class Factory implements QueueEntryListFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java index 5f8ab16c06..414a123c43 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java @@ -51,13 +51,11 @@ public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl _propertyName = propertyName; } - @Override public AMQQueue getQueue() { return _queue; } - @Override public SortedQueueEntryImpl add(final ServerMessage message) { synchronized(_lock) @@ -286,7 +284,6 @@ public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl return (node == null ? Colour.BLACK : node.getColour()) == colour; } - @Override public SortedQueueEntryImpl next(final SortedQueueEntryImpl node) { synchronized(_lock) @@ -316,13 +313,11 @@ public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl } } - @Override public QueueEntryIterator<SortedQueueEntryImpl> iterator() { return new QueueEntryIteratorImpl(_head); } - @Override public SortedQueueEntryImpl getHead() { return _head; @@ -333,7 +328,6 @@ public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl return _root; } - @Override public void entryDeleted(final SortedQueueEntryImpl entry) { synchronized(_lock) @@ -431,6 +425,11 @@ public class SortedQueueEntryList implements QueueEntryList<SortedQueueEntryImpl } } + public int getPriorities() + { + return 0; + } + /** * Swaps the position of the node in the tree with it's successor * (that is the node with the next highest key) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java index fbef23dca1..48f2efb342 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java @@ -21,18 +21,17 @@ 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; - import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.subscription.Subscription; + -class SubFlushRunner implements ReadWriteRunnable +class SubFlushRunner implements Runnable { private static final Logger _logger = Logger.getLogger(SubFlushRunner.class); @@ -90,16 +89,6 @@ class SubFlushRunner implements ReadWriteRunnable return (SimpleAMQQueue) _sub.getQueue(); } - public boolean isRead() - { - return false; - } - - public boolean isWrite() - { - return true; - } - public String toString() { return "SubFlushRunner-" + _sub.getLogActor(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 7eb1b54693..6753cf4560 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -148,7 +148,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry BrokerConfig broker = new BrokerConfigAdapter(instance); - SystemConfig system = (SystemConfig) store.getRoot(); + SystemConfig system = store.getRoot(); system.addBroker(broker); instance.setBroker(broker); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java index 6a36b22400..f77b8d2dfa 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java @@ -165,7 +165,6 @@ public class BrokerConfigAdapter implements BrokerConfig /** * @see org.apache.qpid.server.configuration.BrokerConfig#getFeatures() */ - @Override public List<String> getFeatures() { final List<String> features = new ArrayList<String>(); @@ -176,4 +175,16 @@ public class BrokerConfigAdapter implements BrokerConfig return Collections.unmodifiableList(features); } + + @Override + public String toString() + { + return "BrokerConfigAdapter{" + + "_id=" + _id + + ", _system=" + _system + + ", _vhosts=" + _vhosts + + ", _createTime=" + _createTime + + ", _federationTag='" + _federationTag + '\'' + + '}'; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java index abf9e3379d..2a1ae8a870 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -32,11 +32,9 @@ import static org.apache.qpid.server.security.access.Operation.UNBIND; import java.net.SocketAddress; import java.security.Principal; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import javax.security.auth.Subject; @@ -192,6 +190,15 @@ public class SecurityManager return _logger; } + private static class CachedPropertiesMap extends LinkedHashMap<String, PublishAccessCheck> + { + @Override + protected boolean removeEldestEntry(Entry<String, PublishAccessCheck> eldest) + { + return size() >= 200; + } + } + private abstract class AccessCheck { abstract Result allowed(SecurityPlugin plugin); @@ -204,56 +211,61 @@ public class SecurityManager return true; } - HashMap<String, SecurityPlugin> remainingPlugins = new HashMap<String, SecurityPlugin>(_globalPlugins); + Map<String, SecurityPlugin> remainingPlugins = _globalPlugins.isEmpty() + ? Collections.<String, SecurityPlugin>emptyMap() + : _hostPlugins.isEmpty() ? _globalPlugins : new HashMap<String, SecurityPlugin>(_globalPlugins); - for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet()) + if(!_hostPlugins.isEmpty()) { - // Create set of global only plugins - SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey()); - if (globalPlugin != null) - { - remainingPlugins.remove(hostEntry.getKey()); - } - - Result host = checker.allowed(hostEntry.getValue()); - - if (host == Result.DENIED) - { - // Something vetoed the access, we're done - return false; - } - - // host allow overrides global allow, so only check global on abstain or defer - if (host != Result.ALLOWED) - { - if (globalPlugin == null) - { - if (host == Result.DEFER) - { - host = hostEntry.getValue().getDefault(); - } - if (host == Result.DENIED) + for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet()) + { + // Create set of global only plugins + SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey()); + if (globalPlugin != null) + { + remainingPlugins.remove(hostEntry.getKey()); + } + + Result host = checker.allowed(hostEntry.getValue()); + + if (host == Result.DENIED) + { + // Something vetoed the access, we're done + return false; + } + + // host allow overrides global allow, so only check global on abstain or defer + if (host != Result.ALLOWED) + { + if (globalPlugin == null) { - return false; + if (host == Result.DEFER) + { + host = hostEntry.getValue().getDefault(); + } + if (host == Result.DENIED) + { + return false; + } } - } - else - { - Result global = checker.allowed(globalPlugin); - if (global == Result.DEFER) - { - global = globalPlugin.getDefault(); - } - if (global == Result.ABSTAIN && host == Result.DEFER) - { - global = hostEntry.getValue().getDefault(); - } - if (global == Result.DENIED) + else { - return false; + Result global = checker.allowed(globalPlugin); + if (global == Result.DEFER) + { + global = globalPlugin.getDefault(); + } + if (global == Result.ABSTAIN && host == Result.DEFER) + { + global = hostEntry.getValue().getDefault(); + } + if (global == Result.DENIED) + { + return false; + } } - } - } + } + } } for (SecurityPlugin plugin : remainingPlugins.values()) @@ -371,15 +383,41 @@ public class SecurityManager }); } - public boolean authorisePublish(final boolean immediate, final String routingKey, final String exchangeName) + + private ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> _immediatePublishPropsCache + = new ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>>(); + private ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> _publishPropsCache + = new ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>>(); + + public boolean authorisePublish(final boolean immediate, String routingKey, String exchangeName) { - return checkAllPlugins(new AccessCheck() + if(routingKey == null) { - Result allowed(SecurityPlugin plugin) + routingKey = ""; + } + if(exchangeName == null) + { + exchangeName = ""; + } + PublishAccessCheck check; + ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> cache = + immediate ? _immediatePublishPropsCache : _publishPropsCache; + + ConcurrentHashMap<String, PublishAccessCheck> exchangeMap = cache.get(exchangeName); + if(exchangeMap == null) + { + cache.putIfAbsent(exchangeName, new ConcurrentHashMap<String, PublishAccessCheck>()); + exchangeMap = cache.get(exchangeName); + } + + check = exchangeMap.get(routingKey); + if(check == null) { - return plugin.authorise(PUBLISH, EXCHANGE, new ObjectProperties(exchangeName, routingKey, immediate)); + check = new PublishAccessCheck(new ObjectProperties(exchangeName, routingKey, immediate)); + exchangeMap.put(routingKey, check); } - }); + + return checkAllPlugins(check); } public boolean authorisePurge(final AMQQueue queue) @@ -413,4 +451,19 @@ public class SecurityManager return current; } + + private class PublishAccessCheck extends AccessCheck + { + private final ObjectProperties _props; + + public PublishAccessCheck(ObjectProperties props) + { + _props = props; + } + + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(PUBLISH, EXCHANGE, _props); + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java index e4bf8df340..8a52d31f97 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java @@ -18,10 +18,7 @@ */ package org.apache.qpid.server.security.access; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.apache.commons.lang.StringUtils; import org.apache.qpid.framing.AMQShortString; @@ -35,7 +32,7 @@ import org.apache.qpid.server.queue.AMQQueue; * {@link #equals(Object)} and {@link #hashCode()} are intended for use in maps. This is due to the wildcard matching * described above. */ -public class ObjectProperties extends HashMap<ObjectProperties.Property, String> +public class ObjectProperties { /** serialVersionUID */ private static final long serialVersionUID = -1356019341374170495L; @@ -93,7 +90,9 @@ public class ObjectProperties extends HashMap<ObjectProperties.Property, String> return properties; } } - + + private final EnumMap<Property, String> _properties = new EnumMap<Property, String>(Property.class); + public static List<String> getAllPropertyNames() { List<String> properties = new ArrayList<String>(); @@ -113,7 +112,7 @@ public class ObjectProperties extends HashMap<ObjectProperties.Property, String> { super(); - putAll(copy); + _properties.putAll(copy._properties); } public ObjectProperties(String name) @@ -231,7 +230,7 @@ public class ObjectProperties extends HashMap<ObjectProperties.Property, String> public List<String> getPropertyNames() { List<String> properties = new ArrayList<String>(); - for (Property property : keySet()) + for (Property property : _properties.keySet()) { properties.add(property.getName()); } @@ -240,17 +239,22 @@ public class ObjectProperties extends HashMap<ObjectProperties.Property, String> public Boolean isSet(Property key) { - return containsKey(key) && Boolean.valueOf(get(key)); + return _properties.containsKey(key) && Boolean.valueOf(_properties.get(key)); } - + + public String get(Property key) + { + return _properties.get(key); + } + public String getName() { - return get(Property.NAME); + return _properties.get(Property.NAME); } public void setName(String name) { - put(Property.NAME, name); + _properties.put(Property.NAME, name); } public void setName(AMQShortString name) @@ -262,39 +266,38 @@ public class ObjectProperties extends HashMap<ObjectProperties.Property, String> { return put(key, value == null ? "" : value.asString()); } - - @Override + public String put(Property key, String value) { - return super.put(key, value == null ? "" : value.trim()); + return _properties.put(key, value == null ? "" : value.trim()); } public void put(Property key, Boolean value) { if (value != null) { - super.put(key, Boolean.toString(value)); + _properties.put(key, Boolean.toString(value)); } } public boolean matches(ObjectProperties properties) { - if (properties.keySet().isEmpty()) + if (properties._properties.keySet().isEmpty()) { return true; } - if (!keySet().containsAll(properties.keySet())) + if (!_properties.keySet().containsAll(properties._properties.keySet())) { return false; } - for (Map.Entry<Property,String> entry : properties.entrySet()) + for (Map.Entry<Property,String> entry : properties._properties.entrySet()) { Property key = entry.getKey(); String ruleValue = entry.getValue(); - String thisValue = get(key); + String thisValue = _properties.get(key); if (!valueMatches(thisValue, ruleValue)) { @@ -315,4 +318,29 @@ public class ObjectProperties extends HashMap<ObjectProperties.Property, String> && thisValue.length() > ruleValue.length() && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 2))); } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ObjectProperties that = (ObjectProperties) o; + + if (_properties != null ? !_properties.equals(that._properties) : that._properties != null) return false; + + return true; + } + + @Override + public int hashCode() + { + return _properties != null ? _properties.hashCode() : 0; + } + + @Override + public String toString() + { + return _properties.toString(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java index a883f656be..09e7fe0a11 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java @@ -21,6 +21,9 @@ package org.apache.qpid.server.store; import java.nio.ByteBuffer; +import java.util.Map; +import java.util.UUID; + import org.apache.qpid.framing.FieldTable; public interface ConfigurationRecoveryHandler @@ -42,7 +45,19 @@ public interface ConfigurationRecoveryHandler public static interface BindingRecoveryHandler { void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf); - void completeBindingRecovery(); + BrokerLinkRecoveryHandler completeBindingRecovery(); + } + + public static interface BrokerLinkRecoveryHandler + { + BridgeRecoveryHandler brokerLink(UUID id, long createTime, Map<String,String> arguments); + void completeBrokerLinkRecovery(); + } + + public static interface BridgeRecoveryHandler + { + void bridge(UUID id, long createTime, Map<String,String> arguments); + void completeBridgeRecoveryForLink(); } public static interface QueueEntryRecoveryHandler 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 d3f46d2e90..45083c1595 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,7 +21,9 @@ package org.apache.qpid.server.store; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.lang.ref.SoftReference; @@ -36,7 +38,10 @@ 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.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -47,11 +52,14 @@ import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.federation.Bridge; +import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; import org.apache.qpid.server.logging.messages.MessageStoreMessages; import org.apache.qpid.server.logging.messages.TransactionLogMessages; +import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.queue.AMQQueue; /** @@ -60,7 +68,7 @@ import org.apache.qpid.server.queue.AMQQueue; * * TODO extract the SQL statements into a generic JDBC store */ -public class DerbyMessageStore implements MessageStore +public class DerbyMessageStore implements MessageStore, DurableConfigurationStore { private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class); @@ -80,6 +88,10 @@ public class DerbyMessageStore implements MessageStore private static final String META_DATA_TABLE_NAME = "QPID_META_DATA"; private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT"; + private static final String LINKS_TABLE_NAME = "QPID_LINKS"; + private static final String BRIDGES_TABLE_NAME = "QPID_BRIDGES"; + + private static final int DB_VERSION = 3; @@ -135,6 +147,49 @@ public class DerbyMessageStore implements MessageStore private static final String DELETE_FROM_META_DATA = "DELETE FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?"; private static final String SELECT_ALL_FROM_META_DATA = "SELECT message_id, meta_data FROM " + META_DATA_TABLE_NAME; + private static final String CREATE_LINKS_TABLE = + "CREATE TABLE "+LINKS_TABLE_NAME+" ( id_lsb bigint not null," + + " id_msb bigint not null," + + " create_time bigint not null," + + " arguments blob, PRIMARY KEY ( id_lsb, id_msb ))"; + private static final String SELECT_FROM_LINKS = + "SELECT create_time, arguments FROM " + LINKS_TABLE_NAME + " WHERE id_lsb = ? and id_msb"; + private static final String DELETE_FROM_LINKS = "DELETE FROM " + LINKS_TABLE_NAME + + " WHERE id_lsb = ? and id_msb = ?"; + private static final String SELECT_ALL_FROM_LINKS = "SELECT id_lsb, id_msb, create_time, " + + "arguments FROM " + LINKS_TABLE_NAME; + private static final String FIND_LINK = "SELECT id_lsb, id_msb FROM " + LINKS_TABLE_NAME + " WHERE id_lsb = ? and" + + " id_msb = ?"; + private static final String INSERT_INTO_LINKS = "INSERT INTO " + LINKS_TABLE_NAME + "( id_lsb, " + + "id_msb, create_time, arguments ) values (?, ?, ?, ?)"; + + + private static final String CREATE_BRIDGES_TABLE = + "CREATE TABLE "+BRIDGES_TABLE_NAME+" ( id_lsb bigint not null," + + " id_msb bigint not null," + + " create_time bigint not null," + + " link_id_lsb bigint not null," + + " link_id_msb bigint not null," + + " arguments blob, PRIMARY KEY ( id_lsb, id_msb ))"; + private static final String SELECT_FROM_BRIDGES = + "SELECT create_time, link_id_lsb, link_id_msb, arguments FROM " + + BRIDGES_TABLE_NAME + " WHERE id_lsb = ? and id_msb = ?"; + private static final String DELETE_FROM_BRIDGES = "DELETE FROM " + BRIDGES_TABLE_NAME + + " WHERE id_lsb = ? and id_msb = ?"; + private static final String SELECT_ALL_FROM_BRIDGES = "SELECT id_lsb, id_msb, " + + " create_time," + + " link_id_lsb, link_id_msb, " + + "arguments FROM " + BRIDGES_TABLE_NAME + + " WHERE link_id_lsb = ? and link_id_msb = ?"; + private static final String FIND_BRIDGE = "SELECT id_lsb, id_msb FROM " + BRIDGES_TABLE_NAME + + " WHERE id_lsb = ? and id_msb = ?"; + private static final String INSERT_INTO_BRIDGES = "INSERT INTO " + BRIDGES_TABLE_NAME + "( id_lsb, id_msb, " + + "create_time, " + + "link_id_lsb, link_id_msb, " + + "arguments )" + + " values (?, ?, ?, ?, ?, ?)"; + + private static final String DERBY_SINGLE_DB_SHUTDOWN_CODE = "08006"; @@ -197,12 +252,16 @@ public class DerbyMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { - CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); - if(!_configured) { _logSubject = logSubject; + } + + CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName())); + + if(!_configured) + { commonConfiguration(name, storeConfiguration, logSubject); _configured = true; @@ -219,6 +278,11 @@ public class DerbyMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { + + if(!_configured) + { + _logSubject = logSubject; + } CurrentActor.get().message(_logSubject, TransactionLogMessages.CREATED(this.getClass().getName())); if(!_configured) @@ -283,6 +347,8 @@ public class DerbyMessageStore implements MessageStore createQueueEntryTable(conn); createMetaDataTable(conn); createMessageContentTable(conn); + createLinkTable(conn); + createBridgeTable(conn); conn.close(); } @@ -419,6 +485,40 @@ public class DerbyMessageStore implements MessageStore } + private void createLinkTable(final Connection conn) throws SQLException + { + if(!tableExists(LINKS_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + try + { + stmt.execute(CREATE_LINKS_TABLE); + } + finally + { + stmt.close(); + } + } + } + + + private void createBridgeTable(final Connection conn) throws SQLException + { + if(!tableExists(BRIDGES_TABLE_NAME, conn)) + { + Statement stmt = conn.createStatement(); + try + { + stmt.execute(CREATE_BRIDGES_TABLE); + } + finally + { + stmt.close(); + } + } + } + + private boolean tableExists(final String tableName, final Connection conn) throws SQLException @@ -459,7 +559,8 @@ public class DerbyMessageStore implements MessageStore List<String> exchanges = loadExchanges(erh); ConfigurationRecoveryHandler.BindingRecoveryHandler brh = erh.completeExchangeRecovery(); recoverBindings(brh, exchanges); - brh.completeBindingRecovery(); + ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh = brh.completeBindingRecovery(); + recoverBrokerLinks(lrh); } catch (SQLException e) { @@ -470,6 +571,144 @@ public class DerbyMessageStore implements MessageStore } + private void recoverBrokerLinks(final ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh) + throws SQLException + { + _logger.info("Recovering broker links..."); + + Connection conn = null; + try + { + conn = newAutoCommitConnection(); + + PreparedStatement stmt = conn.prepareStatement(SELECT_ALL_FROM_LINKS); + + try + { + ResultSet rs = stmt.executeQuery(); + + try + { + + while(rs.next()) + { + UUID id = new UUID(rs.getLong(2), rs.getLong(1)); + long createTime = rs.getLong(3); + Blob argumentsAsBlob = rs.getBlob(4); + + byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length()); + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dataAsBytes)); + int size = dis.readInt(); + + Map<String,String> arguments = new HashMap<String, String>(); + + for(int i = 0; i < size; i++) + { + arguments.put(dis.readUTF(), dis.readUTF()); + } + + ConfigurationRecoveryHandler.BridgeRecoveryHandler brh = lrh.brokerLink(id, createTime, arguments); + + recoverBridges(brh, id); + + } + } + catch (IOException e) + { + throw new SQLException(e.getMessage(), e); + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } + + } + finally + { + if(conn != null) + { + conn.close(); + } + } + + } + + private void recoverBridges(final ConfigurationRecoveryHandler.BridgeRecoveryHandler brh, final UUID linkId) + throws SQLException + { + _logger.info("Recovering bridges for link " + linkId + "..."); + + Connection conn = null; + try + { + conn = newAutoCommitConnection(); + + PreparedStatement stmt = conn.prepareStatement(SELECT_ALL_FROM_BRIDGES); + stmt.setLong(1, linkId.getLeastSignificantBits()); + stmt.setLong(2, linkId.getMostSignificantBits()); + + + try + { + ResultSet rs = stmt.executeQuery(); + + try + { + + while(rs.next()) + { + UUID id = new UUID(rs.getLong(2), rs.getLong(1)); + long createTime = rs.getLong(3); + Blob argumentsAsBlob = rs.getBlob(6); + + byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length()); + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dataAsBytes)); + int size = dis.readInt(); + + Map<String,String> arguments = new HashMap<String, String>(); + + for(int i = 0; i < size; i++) + { + arguments.put(dis.readUTF(), dis.readUTF()); + } + + brh.bridge(id, createTime, arguments); + + } + brh.completeBridgeRecoveryForLink(); + } + catch (IOException e) + { + throw new SQLException(e.getMessage(), e); + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } + + } + finally + { + if(conn != null) + { + conn.close(); + } + } + + } + private void loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException { Connection conn = newAutoCommitConnection(); @@ -697,7 +936,7 @@ public class DerbyMessageStore implements MessageStore if (results == 0) { - throw new RuntimeException("Message metadata not found for message id " + messageId); + _logger.warn("Message metadata not found for message id " + messageId); } if (_logger.isDebugEnabled()) @@ -1180,6 +1419,233 @@ public class DerbyMessageStore implements MessageStore } + public void createBrokerLink(final BrokerLink link) throws AMQStoreException + { + _logger.debug("public void createBrokerLink(BrokerLink = " + link + "): called"); + + if (_state != State.RECOVERING) + { + try + { + Connection conn = newAutoCommitConnection(); + + PreparedStatement stmt = conn.prepareStatement(FIND_LINK); + try + { + + stmt.setLong(1, link.getId().getLeastSignificantBits()); + stmt.setLong(2, link.getId().getMostSignificantBits()); + ResultSet rs = stmt.executeQuery(); + try + { + + // If we don't have any data in the result set then we can add this queue + if (!rs.next()) + { + PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_LINKS); + + try + { + + insertStmt.setLong(1, link.getId().getLeastSignificantBits()); + insertStmt.setLong(2, link.getId().getMostSignificantBits()); + insertStmt.setLong(3, link.getCreateTime()); + + byte[] argumentBytes = convertStringMapToBytes(link.getArguments()); + ByteArrayInputStream bis = new ByteArrayInputStream(argumentBytes); + + insertStmt.setBinaryStream(4,bis,argumentBytes.length); + + insertStmt.execute(); + } + finally + { + insertStmt.close(); + } + } + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } + conn.close(); + + } + catch (SQLException e) + { + throw new AMQStoreException("Error writing " + link + " to database: " + e.getMessage(), e); + } + } + } + + private byte[] convertStringMapToBytes(final Map<String, String> arguments) throws AMQStoreException + { + byte[] argumentBytes; + if(arguments == null) + { + argumentBytes = new byte[0]; + } + else + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(bos); + + + try + { + dos.writeInt(arguments.size()); + for(Map.Entry<String,String> arg : arguments.entrySet()) + { + dos.writeUTF(arg.getKey()); + dos.writeUTF(arg.getValue()); + } + } + catch (IOException e) + { + // This should never happen + throw new AMQStoreException(e.getMessage(), e); + } + argumentBytes = bos.toByteArray(); + } + return argumentBytes; + } + + public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException + { + _logger.debug("public void deleteBrokerLink( " + link + "): called"); + Connection conn = null; + PreparedStatement stmt = null; + try + { + conn = newAutoCommitConnection(); + stmt = conn.prepareStatement(DELETE_FROM_LINKS); + stmt.setLong(1, link.getId().getLeastSignificantBits()); + stmt.setLong(2, link.getId().getMostSignificantBits()); + int results = stmt.executeUpdate(); + + if (results == 0) + { + throw new AMQStoreException("Link " + link + " not found"); + } + } + catch (SQLException e) + { + throw new AMQStoreException("Error deleting Link " + link + " from database: " + e.getMessage(), e); + } + finally + { + closePreparedStatement(stmt); + closeConnection(conn); + } + + + } + + public void createBridge(final Bridge bridge) throws AMQStoreException + { + _logger.debug("public void createBridge(BrokerLink = " + bridge + "): called"); + + if (_state != State.RECOVERING) + { + try + { + Connection conn = newAutoCommitConnection(); + + PreparedStatement stmt = conn.prepareStatement(FIND_BRIDGE); + try + { + + UUID id = bridge.getId(); + stmt.setLong(1, id.getLeastSignificantBits()); + stmt.setLong(2, id.getMostSignificantBits()); + ResultSet rs = stmt.executeQuery(); + try + { + + // If we don't have any data in the result set then we can add this queue + if (!rs.next()) + { + PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_BRIDGES); + + try + { + + insertStmt.setLong(1, id.getLeastSignificantBits()); + insertStmt.setLong(2, id.getMostSignificantBits()); + + insertStmt.setLong(3, bridge.getCreateTime()); + + UUID linkId = bridge.getLink().getId(); + insertStmt.setLong(4, linkId.getLeastSignificantBits()); + insertStmt.setLong(5, linkId.getMostSignificantBits()); + + byte[] argumentBytes = convertStringMapToBytes(bridge.getArguments()); + ByteArrayInputStream bis = new ByteArrayInputStream(argumentBytes); + + insertStmt.setBinaryStream(6,bis,argumentBytes.length); + + insertStmt.execute(); + } + finally + { + insertStmt.close(); + } + } + } + finally + { + rs.close(); + } + } + finally + { + stmt.close(); + } + conn.close(); + + } + catch (SQLException e) + { + throw new AMQStoreException("Error writing " + bridge + " to database: " + e.getMessage(), e); + } + } + } + + public void deleteBridge(final Bridge bridge) throws AMQStoreException + { + _logger.debug("public void deleteBridge( " + bridge + "): called"); + Connection conn = null; + PreparedStatement stmt = null; + try + { + conn = newAutoCommitConnection(); + stmt = conn.prepareStatement(DELETE_FROM_BRIDGES); + stmt.setLong(1, bridge.getId().getLeastSignificantBits()); + stmt.setLong(2, bridge.getId().getMostSignificantBits()); + int results = stmt.executeUpdate(); + + if (results == 0) + { + throw new AMQStoreException("Bridge " + bridge + " not found"); + } + } + catch (SQLException e) + { + throw new AMQStoreException("Error deleting bridge " + bridge + " from database: " + e.getMessage(), e); + } + finally + { + closePreparedStatement(stmt); + closeConnection(conn); + } + + } + public Transaction newTransaction() { return new DerbyTransaction(); @@ -1678,14 +2144,26 @@ public class DerbyMessageStore implements MessageStore } } - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { - DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, messageId); + if(message.getStoredMessage() instanceof StoredDerbyMessage) + { + try + { + ((StoredDerbyMessage)message.getStoredMessage()).store(_connWrapper.getConnection()); + } + catch (SQLException e) + { + throw new AMQStoreException("Exception on enqueuing message " + _messageId, e); + } + } + + DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, message.getMessageNumber()); } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { - DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, messageId); + DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, message.getMessageNumber()); } @@ -1709,8 +2187,11 @@ public class DerbyMessageStore implements MessageStore { private final long _messageId; + private StorableMessageMetaData _metaData; private volatile SoftReference<StorableMessageMetaData> _metaDataRef; - private Connection _conn; + private byte[] _data; + private volatile SoftReference<byte[]> _dataRef; + StoredDerbyMessage(long messageId, StorableMessageMetaData metaData) { @@ -1721,27 +2202,19 @@ public class DerbyMessageStore implements MessageStore StoredDerbyMessage(long messageId, StorableMessageMetaData metaData, boolean persist) { - try - { - _messageId = messageId; + _messageId = messageId; + - _metaDataRef = new SoftReference<StorableMessageMetaData>(metaData); - if(persist) - { - _conn = newConnection(); - storeMetaData(_conn, messageId, metaData); - } - } - catch (SQLException e) + _metaDataRef = new SoftReference<StorableMessageMetaData>(metaData); + if(persist) { - throw new RuntimeException(e); + _metaData = metaData; } - } public StorableMessageMetaData getMetaData() { - StorableMessageMetaData metaData = _metaDataRef.get(); + StorableMessageMetaData metaData = _metaData == null ? _metaDataRef.get() : _metaData; if(metaData == null) { try @@ -1765,27 +2238,62 @@ public class DerbyMessageStore implements MessageStore public void addContent(int offsetInMessage, java.nio.ByteBuffer src) { - DerbyMessageStore.this.addContent(_conn, _messageId, offsetInMessage, src); + src = src.slice(); + + if(_data == null) + { + _data = new byte[src.remaining()]; + _dataRef = new SoftReference<byte[]>(_data); + src.duplicate().get(_data); + } + else + { + byte[] oldData = _data; + _data = new byte[oldData.length + src.remaining()]; + _dataRef = new SoftReference<byte[]>(_data); + + System.arraycopy(oldData,0,_data,0,oldData.length); + src.duplicate().get(_data, oldData.length, src.remaining()); + } + } public int getContent(int offsetInMessage, java.nio.ByteBuffer dst) { - return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst); + byte[] data = _dataRef == null ? null : _dataRef.get(); + if(data != null) + { + int length = Math.min(dst.remaining(), data.length - offsetInMessage); + dst.put(data, offsetInMessage, length); + return length; + } + else + { + return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst); + } + } + + + public ByteBuffer getContent(int offsetInMessage, int size) + { + ByteBuffer buf = ByteBuffer.allocate(size); + getContent(offsetInMessage, buf); + buf.position(0); + return buf; } - public StoreFuture flushToStore() + public synchronized StoreFuture flushToStore() { try { - if(_conn != null) + if(_metaData != null) { - if(_logger.isDebugEnabled()) - { - _logger.debug("Flushing message " + _messageId + " to store"); - } + Connection conn = newConnection(); + + store(conn); - _conn.commit(); - _conn.close(); + conn.commit(); + conn.close(); } } catch (SQLException e) @@ -1796,16 +2304,34 @@ public class DerbyMessageStore implements MessageStore } throw new RuntimeException(e); } - finally + return IMMEDIATE_FUTURE; + } + + private synchronized void store(final Connection conn) throws SQLException + { + if(_metaData != null) { - _conn = null; + try + { + storeMetaData(conn, _messageId, _metaData); + DerbyMessageStore.this.addContent(conn, _messageId, 0, + _data == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(_data)); + } + finally + { + _metaData = null; + _data = null; + } + } + + if(_logger.isDebugEnabled()) + { + _logger.debug("Storing message " + _messageId + " to store"); } - return IMMEDIATE_FUTURE; } public void remove() { - flushToStore(); DerbyMessageStore.this.removeMessage(_messageId); } } @@ -1839,4 +2365,5 @@ public class DerbyMessageStore implements MessageStore } } } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java index 5fb23653cb..9cd2567b7d 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java @@ -25,6 +25,8 @@ import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.federation.Bridge; +import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.queue.AMQQueue; @@ -128,4 +130,12 @@ public interface DurableConfigurationStore * @throws AMQStoreException If the operation fails for any reason. */ void updateQueue(AMQQueue queue) throws AMQStoreException; + + void createBrokerLink(BrokerLink link) throws AMQStoreException; + + void deleteBrokerLink(BrokerLink link) throws AMQStoreException; + + void createBridge(Bridge bridge) throws AMQStoreException; + + void deleteBridge(Bridge bridge) throws AMQStoreException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index d008d42fa0..c5393f73a2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -31,14 +31,18 @@ import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.federation.Bridge; +import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; import org.apache.qpid.server.logging.messages.MessageStoreMessages; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; /** A simple message store that stores the messages in a threadsafe structure in memory. */ -public class MemoryMessageStore implements MessageStore +public class MemoryMessageStore implements MessageStore, DurableConfigurationStore { private static final Logger _log = Logger.getLogger(MemoryMessageStore.class); @@ -53,11 +57,11 @@ public class MemoryMessageStore implements MessageStore private static final Transaction IN_MEMORY_TRANSACTION = new Transaction() { - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { } @@ -155,6 +159,26 @@ public class MemoryMessageStore implements MessageStore // Not required to do anything } + public void createBrokerLink(final BrokerLink link) throws AMQStoreException + { + + } + + public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException + { + + } + + public void createBridge(final Bridge bridge) throws AMQStoreException + { + + } + + public void deleteBridge(final Bridge bridge) throws AMQStoreException + { + + } + public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler, Configuration storeConfiguration, 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 e2fca2f9c7..88c95ad65e 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,14 +20,16 @@ */ package org.apache.qpid.server.store; +import org.apache.qpid.AMQStoreException; import org.apache.qpid.server.logging.LogSubject; import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.message.EnqueableMessage; /** * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages. * */ -public interface MessageStore extends DurableConfigurationStore, TransactionLog +public interface MessageStore { StoreFuture IMMEDIATE_FUTURE = new StoreFuture() { @@ -77,4 +79,69 @@ public interface MessageStore extends DurableConfigurationStore, TransactionLog boolean isPersistent(); + + 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 message + * @throws org.apache.qpid.AMQStoreException If the operation fails for any reason. + */ + void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException; + + /** + * Extracts a message from a specified queue, in a given transactional context. + * + * @param queue The queue to place the message on. + * @param message The message to dequeue. + * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. + */ + void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException; + + + /** + * Commits all operations performed within a given transactional context. + * + * @throws AMQStoreException If the operation fails for any reason. + */ + void commitTran() throws AMQStoreException; + + /** + * Commits all operations performed within a given transactional context. + * + * @throws AMQStoreException If the operation fails for any reason. + */ + StoreFuture commitTranAsync() throws AMQStoreException; + + /** + * Abandons all operations performed within a given transactional context. + * + * @throws AMQStoreException If the operation fails for any reason. + */ + void abortTran() throws AMQStoreException; + + + + } + + 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/StorableMessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java index 2381301c30..12d2a6a6c7 100755 --- 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 @@ -30,5 +30,7 @@ public interface StorableMessageMetaData int writeToBuffer(int offsetInMetaData, ByteBuffer dest); + int getContentSize(); + boolean isPersistent(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java index fba4745523..144cc629bd 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java @@ -42,36 +42,87 @@ public class StoredMemoryMessage implements StoredMessage public void addContent(int offsetInMessage, ByteBuffer src) { - src = src.duplicate(); - if(_content == null || offsetInMessage + src.remaining() > _content.capacity()) + if(_content == null) { - ByteBuffer newContent = ByteBuffer.allocate(offsetInMessage+src.remaining()); - if(_content != null) + if(offsetInMessage == 0) { - newContent.duplicate().put(_content.array()); + _content = src.slice(); + } + else + { + final int contentSize = _metaData.getContentSize(); + int size = (contentSize < offsetInMessage + src.remaining()) + ? offsetInMessage + src.remaining() + : contentSize; + _content = ByteBuffer.allocate(size); + addContent(offsetInMessage, src); } - _content = newContent; } + else + { + if(_content.limit() >= offsetInMessage + src.remaining()) + { + _content.position(offsetInMessage); + _content.put(src); + _content.position(0); + } + else + { + final int contentSize = _metaData.getContentSize(); + int size = (contentSize < offsetInMessage + src.remaining()) + ? offsetInMessage + src.remaining() + : contentSize; + ByteBuffer oldContent = _content; + _content = ByteBuffer.allocate(size); + _content.put(oldContent); + _content.position(0); + addContent(offsetInMessage, src); + } - 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()) + if(_content == null) { - src.limit(dst.remaining()); + return 0; } + ByteBuffer src = _content.duplicate(); + + int oldPosition = src.position(); + + src.position(oldPosition + offset); + + int length = dst.remaining() < src.remaining() ? dst.remaining() : src.remaining(); + src.limit(oldPosition + length); + dst.put(src); - return src.limit(); + + + return length; + } + + + public ByteBuffer getContent(int offsetInMessage, int size) + { + if(_content == null) + { + return null; + } + ByteBuffer buf = _content.duplicate(); + + if(offsetInMessage != 0) + { + buf.position(offsetInMessage); + buf = buf.slice(); + } + + buf.limit(size); + return buf; } - public TransactionLog.StoreFuture flushToStore() + public MessageStore.StoreFuture flushToStore() { return MessageStore.IMMEDIATE_FUTURE; } 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 index 0bc45c6718..d4a0381929 100755 --- 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 @@ -32,7 +32,9 @@ public interface StoredMessage<M extends StorableMessageMetaData> int getContent(int offsetInMessage, ByteBuffer dst); - TransactionLog.StoreFuture flushToStore(); + ByteBuffer getContent(int offsetInMessage, int size); + + MessageStore.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 index d196a91930..da7f8d18b2 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java @@ -20,72 +20,7 @@ */ package org.apache.qpid.server.store; -import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.AMQStoreException; -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 AMQStoreException If the operation fails for any reason. - */ - void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException; - - /** - * Extracts a message from a specified queue, in a given transactional context. - * - * @param queue The queue to place the message on. - * @param messageId The message to dequeue. - * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist. - */ - void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException; - - - /** - * Commits all operations performed within a given transactional context. - * - * @throws AMQStoreException If the operation fails for any reason. - */ - void commitTran() throws AMQStoreException; - - /** - * Commits all operations performed within a given transactional context. - * - * @throws AMQStoreException If the operation fails for any reason. - */ - StoreFuture commitTranAsync() throws AMQStoreException; - - /** - * Abandons all operations performed within a given transactional context. - * - * @throws AMQStoreException If the operation fails for any reason. - */ - void abortTran() throws AMQStoreException; - - - - } - - 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 index 7781c52df3..802596ed1e 100755 --- 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 @@ -22,7 +22,7 @@ package org.apache.qpid.server.store; public interface TransactionLogRecoveryHandler { - QueueEntryRecoveryHandler begin(TransactionLog log); + QueueEntryRecoveryHandler begin(MessageStore log); public static interface QueueEntryRecoveryHandler { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java new file mode 100644 index 0000000000..f511cc0dc9 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java @@ -0,0 +1,150 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * 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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; + + +public class AssignedSubscriptionMessageGroupManager implements MessageGroupManager +{ + private static final Logger _logger = LoggerFactory.getLogger(AssignedSubscriptionMessageGroupManager.class); + + + private final String _groupId; + private final ConcurrentHashMap<Integer, Subscription> _groupMap = new ConcurrentHashMap<Integer, Subscription>(); + private final int _groupMask; + + public AssignedSubscriptionMessageGroupManager(final String groupId, final int maxGroups) + { + _groupId = groupId; + _groupMask = pow2(maxGroups)-1; + } + + private static int pow2(final int i) + { + int val = 1; + while(val < i) val<<=1; + return val; + } + + public Subscription getAssignedSubscription(final QueueEntry entry) + { + Object groupVal = entry.getMessage().getMessageHeader().getHeader(_groupId); + return groupVal == null ? null : _groupMap.get(groupVal.hashCode() & _groupMask); + } + + public boolean acceptMessage(Subscription sub, QueueEntry entry) + { + Object groupVal = entry.getMessage().getMessageHeader().getHeader(_groupId); + if(groupVal == null) + { + return true; + } + else + { + Integer group = groupVal.hashCode() & _groupMask; + Subscription assignedSub = _groupMap.get(group); + if(assignedSub == sub) + { + return true; + } + else + { + if(assignedSub == null) + { + if(_logger.isDebugEnabled()) + { + _logger.debug("Assigning group " + groupVal + " to sub " + sub); + } + assignedSub = _groupMap.putIfAbsent(group, sub); + return assignedSub == null || assignedSub == sub; + } + else + { + return false; + } + } + } + } + + public QueueEntry findEarliestAssignedAvailableEntry(Subscription sub) + { + EntryFinder visitor = new EntryFinder(sub); + sub.getQueue().visit(visitor); + return visitor.getEntry(); + } + + private class EntryFinder implements AMQQueue.Visitor + { + private QueueEntry _entry; + private Subscription _sub; + + public EntryFinder(final Subscription sub) + { + _sub = sub; + } + + public boolean visit(final QueueEntry entry) + { + if(!entry.isAvailable()) + return false; + + Object groupId = entry.getMessage().getMessageHeader().getHeader(_groupId); + if(groupId == null) + return false; + + Integer group = groupId.hashCode() & _groupMask; + Subscription assignedSub = _groupMap.get(group); + if(assignedSub == _sub) + { + _entry = entry; + return true; + } + else + { + return false; + } + } + + public QueueEntry getEntry() + { + return _entry; + } + } + + public void clearAssignments(Subscription sub) + { + Iterator<Subscription> subIter = _groupMap.values().iterator(); + while(subIter.hasNext()) + { + if(subIter.next() == sub) + { + subIter.remove(); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java new file mode 100644 index 0000000000..42818db214 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java @@ -0,0 +1,270 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.subscription; + +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +public class DefinedGroupMessageGroupManager implements MessageGroupManager +{ + private static final Logger _logger = LoggerFactory.getLogger(DefinedGroupMessageGroupManager.class); + + private final String _groupId; + private final String _defaultGroup; + private final Map<Object, Group> _groupMap = new HashMap<Object, Group>(); + private final SubscriptionResetHelper _resetHelper; + + private final class Group + { + private final Object _group; + private Subscription _subscription; + private int _activeCount; + + private Group(final Object key, final Subscription subscription) + { + _group = key; + _subscription = subscription; + } + + public boolean add() + { + if(_subscription != null) + { + _activeCount++; + return true; + } + else + { + return false; + } + } + + public void subtract() + { + if(--_activeCount == 0) + { + _resetHelper.resetSubPointersForGroups(_subscription, false); + _subscription = null; + _groupMap.remove(_group); + } + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + Group group = (Group) o; + + return _group.equals(group._group); + } + + @Override + public int hashCode() + { + return _group.hashCode(); + } + + public boolean isValid() + { + return !(_subscription == null || (_activeCount == 0 && _subscription.isClosed())); + } + + public Subscription getSubscription() + { + return _subscription; + } + + @Override + public String toString() + { + return "Group{" + + "_group=" + _group + + ", _subscription=" + _subscription + + ", _activeCount=" + _activeCount + + '}'; + } + } + + public DefinedGroupMessageGroupManager(final String groupId, String defaultGroup, SubscriptionResetHelper resetHelper) + { + _groupId = groupId; + _defaultGroup = defaultGroup; + _resetHelper = resetHelper; + } + + public synchronized Subscription getAssignedSubscription(final QueueEntry entry) + { + Object groupId = getKey(entry); + + Group group = _groupMap.get(groupId); + return group == null || !group.isValid() ? null : group.getSubscription(); + } + + public synchronized boolean acceptMessage(final Subscription sub, final QueueEntry entry) + { + Object groupId = getKey(entry); + Group group = _groupMap.get(groupId); + + if(group == null || !group.isValid()) + { + group = new Group(groupId, sub); + + _groupMap.put(groupId, group); + + // there's a small change that the group became empty between the point at which getNextAvailable() was + // called on the subscription, and when accept message is called... in that case we want to avoid delivering + // out of order + if(_resetHelper.isEntryAheadOfSubscription(entry, sub)) + { + return false; + } + + } + + Subscription assignedSub = group.getSubscription(); + + if(assignedSub == sub) + { + entry.addStateChangeListener(new GroupStateChangeListener(group, entry)); + return true; + } + else + { + return false; + } + } + + + public synchronized QueueEntry findEarliestAssignedAvailableEntry(final Subscription sub) + { + EntryFinder visitor = new EntryFinder(sub); + sub.getQueue().visit(visitor); + _logger.debug("Earliest available entry for " + sub + " is " + visitor.getEntry() + (visitor.getEntry() == null ? "" : " : " + getKey(visitor.getEntry()))); + return visitor.getEntry(); + } + + private class EntryFinder implements AMQQueue.Visitor + { + private QueueEntry _entry; + private Subscription _sub; + + public EntryFinder(final Subscription sub) + { + _sub = sub; + } + + public boolean visit(final QueueEntry entry) + { + if(!entry.isAvailable()) + return false; + + Object groupId = getKey(entry); + + Group group = _groupMap.get(groupId); + if(group != null && group.getSubscription() == _sub) + { + _entry = entry; + return true; + } + else + { + return false; + } + } + + public QueueEntry getEntry() + { + return _entry; + } + } + + + public void clearAssignments(final Subscription sub) + { + } + + private Object getKey(QueueEntry entry) + { + ServerMessage message = entry.getMessage(); + AMQMessageHeader messageHeader = message == null ? null : message.getMessageHeader(); + Object groupVal = messageHeader == null ? _defaultGroup : messageHeader.getHeader(_groupId); + if(groupVal == null) + { + groupVal = _defaultGroup; + } + return groupVal; + } + + private class GroupStateChangeListener implements QueueEntry.StateChangeListener + { + private final Group _group; + + public GroupStateChangeListener(final Group group, + final QueueEntry entry) + { + _group = group; + } + + public void stateChanged(final QueueEntry entry, + final QueueEntry.State oldState, + final QueueEntry.State newState) + { + synchronized (DefinedGroupMessageGroupManager.this) + { + if(_group.isValid()) + { + if(oldState != newState) + { + if(newState == QueueEntry.State.ACQUIRED) + { + _logger.debug("Adding to " + _group); + _group.add(); + } + else if(oldState == QueueEntry.State.ACQUIRED) + { + _logger.debug("Subtracting from " + _group); + _group.subtract(); + } + } + } + else + { + entry.removeStateChangeListener(this); + } + } + } + } +} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/Expression.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageGroupManager.java index 8208f49688..8ce4ce3344 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/Expression.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageGroupManager.java @@ -1,35 +1,41 @@ -/* Licensed to the Apache Software Foundation (ASF) under one +/* + * + * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * */ -package org.apache.qpid.filter; +package org.apache.qpid.server.subscription; -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; +import org.apache.qpid.server.queue.QueueEntry; - -/** - * Represents an expression - */ -public interface Expression +public interface MessageGroupManager { - /** - * @param message The message to evaluate - * @return the value of this expression - * @throws AMQInternalException - */ - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException; + public interface SubscriptionResetHelper + { + public void resetSubPointersForGroups(Subscription subscription, boolean clearAssignments); + + boolean isEntryAheadOfSubscription(QueueEntry entry, Subscription sub); + } + + Subscription getAssignedSubscription(QueueEntry entry); + + boolean acceptMessage(Subscription sub, QueueEntry entry); + + QueueEntry findEarliestAssignedAvailableEntry(Subscription sub); + + void clearAssignments(Subscription sub); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 6db58ce9c1..1e36119ce8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -62,7 +62,6 @@ import org.apache.qpid.transport.MessageProperties; import org.apache.qpid.transport.MessageTransfer; import org.apache.qpid.transport.Method; import org.apache.qpid.transport.Option; -import org.apache.qpid.transport.Session; import org.apache.qpid.transport.Struct; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -70,10 +69,10 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.locks.Lock; @@ -183,6 +182,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue()); } _queue = queue; + Map<String, Object> arguments = queue.getArguments() == null ? Collections.EMPTY_MAP : queue.getArguments(); _traceExclude = (String) arguments.get("qpid.trace.exclude"); _trace = (String) arguments.get("qpid.trace.id"); @@ -219,8 +219,8 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr if (_noLocal && entry.getMessage() instanceof MessageTransferMessage) { - Session messageSession= ((MessageTransferMessage)entry.getMessage()).getSession(); - if (messageSession != null && messageSession.getConnection() == _session.getConnection()) + Object connectionRef = ((MessageTransferMessage)entry.getMessage()).getConnectionReference(); + if (connectionRef != null && connectionRef == _session.getReference()) { return false; } @@ -366,35 +366,8 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { 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 - { - if(header instanceof MessageProperties) - { - messageProps = (MessageProperties) header; - } - newHeaders.add(header); - } - } + DeliveryProperties origDeliveryProps = msg.getHeader() == null ? null : msg.getHeader().getDeliveryProperties(); + messageProps = msg.getHeader() == null ? null : msg.getHeader().getMessageProperties(); deliveryProps = new DeliveryProperties(); if(origDeliveryProps != null) @@ -429,17 +402,16 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr deliveryProps.setRedelivered(entry.isRedelivered()); - newHeaders.add(deliveryProps); - if(_trace != null && messageProps == null) { messageProps = new MessageProperties(); - newHeaders.add(messageProps); } - Header header = new Header(newHeaders); + Header header = new Header(deliveryProps, messageProps, msg.getHeader() == null ? null : msg.getHeader().getNonStandardProperties()); - xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody()); + + xfr = batch ? new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody(), BATCHED) + : new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody()); } else if(serverMsg instanceof AMQMessage) { @@ -452,8 +424,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr message_0_8.getContent(body, 0); body.flip(); - Struct[] headers = new Struct[] { deliveryProps, messageProps }; - BasicContentHeaderProperties properties = (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().getProperties(); final AMQShortString exchange = message_0_8.getMessagePublishInfo().getExchange(); @@ -494,8 +464,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr messageProps.setApplicationHeaders(appHeaders); - Header header = new Header(headers); - xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); + Header header = new Header(deliveryProps, messageProps, null); + xfr = batch ? new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body, BATCHED) + : new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); } else { @@ -508,8 +479,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr serverMsg.getContent(body, 0); body.flip(); - Struct[] headers = new Struct[] { deliveryProps, messageProps }; - deliveryProps.setExpiration(serverMsg.getExpiration()); deliveryProps.setImmediate(serverMsg.isImmediate()); @@ -556,8 +525,9 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr messageProps.setApplicationHeaders(appHeaders); */ - Header header = new Header(headers); - xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); + Header header = new Header(deliveryProps, messageProps, null); + xfr = batch ? new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body, BATCHED) + : new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body); } boolean excludeDueToFederation = false; @@ -633,28 +603,47 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } } - private void forceDequeue(final QueueEntry entry, final boolean restoreCredit) + private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit) { - ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog()); - txn.dequeue(entry.getQueue(),entry.getMessage(), - new ServerTransaction.Action() - { - public void postCommit() - { - if(restoreCredit) - { - restoreCredit(entry); - } - entry.discard(); - } + _deferredMessageCredit += deferredMessageCredit; + _deferredSizeCredit += deferredSizeCredit; - public void onRollback() - { + } - } - }); + public void flushCreditState(boolean strict) + { + if(strict || !isSuspended() || _deferredMessageCredit >= 200 + || !(_creditManager instanceof WindowCreditManager) + || ((WindowCreditManager)_creditManager).getMessageCreditLimit() < 400 ) + { + _creditManager.restoreCredit(_deferredMessageCredit, _deferredSizeCredit); + _deferredMessageCredit = 0; + _deferredSizeCredit = 0l; + } } + private void forceDequeue(final QueueEntry entry, final boolean restoreCredit) + { + AutoCommitTransaction dequeueTxn = new AutoCommitTransaction(getQueue().getVirtualHost().getMessageStore()); + dequeueTxn.dequeue(entry.getQueue(), entry.getMessage(), + new ServerTransaction.Action() + { + public void postCommit() + { + if (restoreCredit) + { + restoreCredit(entry); + } + entry.discard(); + } + + public void onRollback() + { + + } + }); + } + void reject(final QueueEntry entry) { entry.setRedelivered(); @@ -693,7 +682,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { final InboundMessage m = new InboundMessageAdapter(entry); - final ArrayList<? extends BaseQueue> destinationQueues = alternateExchange.route(m); + final List<? extends BaseQueue> destinationQueues = alternateExchange.route(m); if (destinationQueues == null || destinationQueues.isEmpty()) { @@ -740,6 +729,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr return _stateChangeLock.tryLock(); } + public void getSendLock() { _stateChangeLock.lock(); @@ -800,28 +790,6 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr return _properties.get(key); } - private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit) - { - _deferredMessageCredit += deferredMessageCredit; - _deferredSizeCredit += deferredSizeCredit; - - } - - public void flushCreditState() - { - flushCreditState(false); - } - public void flushCreditState(boolean strict) - { - if(strict || !isSuspended() || _deferredMessageCredit >= 200 - || !(_creditManager instanceof WindowCreditManager) - || ((WindowCreditManager)_creditManager).getMessageCreditLimit() < 400 ) - { - _creditManager.restoreCredit(_deferredMessageCredit, _deferredSizeCredit); - _deferredMessageCredit = 0; - _deferredSizeCredit = 0l; - } - } public FlowCreditManager_0_10 getCreditManager() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index 00f0c9f0f1..ab07ed20f6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -75,7 +75,7 @@ public class ServerConnection extends Connection implements Managable, AMQConnec private boolean _statisticsEnabled = false; private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private final long _connectionId; - + private final Object _reference = new Object(); private ServerConnectionMBean _mBean; private VirtualHost _virtualHost; private AtomicLong _lastIoTime = new AtomicLong(); @@ -90,6 +90,11 @@ public class ServerConnection extends Connection implements Managable, AMQConnec return _config.getId(); } + public Object getReference() + { + return _reference; + } + @Override protected void invoke(Method method) { @@ -414,13 +419,11 @@ public class ServerConnection extends Connection implements Managable, AMQConnec return _connectionId; } - @Override public boolean isSessionNameUnique(byte[] name) { return !super.hasSessionWithName(name); } - @Override public String getUserName() { return _authorizedPrincipal.getName(); @@ -450,11 +453,11 @@ public class ServerConnection extends Connection implements Managable, AMQConnec { for (Session ssn : getChannels()) { - ((ServerSession)ssn).flushCreditState(); + ((ServerSession)ssn).receivedComplete(); } } - @Override + public ManagedObject getManagedObject() { return _mBean; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 23b77b1fd9..2142b2f7c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -23,10 +23,8 @@ package org.apache.qpid.server.transport; import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT; import static org.apache.qpid.util.Serial.gt; -import java.lang.ref.WeakReference; import java.security.Principal; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -34,8 +32,11 @@ import java.util.Map; import java.util.SortedMap; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javax.security.auth.Subject; import org.apache.qpid.AMQException; @@ -51,6 +52,7 @@ import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.messages.ChannelMessages; +import org.apache.qpid.server.logging.subjects.ChannelLogSubject; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.protocol.AMQConnectionModel; @@ -67,10 +69,16 @@ import org.apache.qpid.server.txn.ServerTransaction; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.transport.Binary; import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.MessageCreditUnit; +import org.apache.qpid.transport.MessageFlow; +import org.apache.qpid.transport.MessageFlowMode; +import org.apache.qpid.transport.MessageSetFlowMode; +import org.apache.qpid.transport.MessageStop; import org.apache.qpid.transport.MessageTransfer; import org.apache.qpid.transport.Method; import org.apache.qpid.transport.Range; import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.RangeSetFactory; import org.apache.qpid.transport.Session; import org.apache.qpid.transport.SessionDelegate; import org.slf4j.Logger; @@ -81,11 +89,20 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi private static final Logger _logger = LoggerFactory.getLogger(ServerSession.class); private static final String NULL_DESTINTATION = UUID.randomUUID().toString(); + private static final int PRODUCER_CREDIT_TOPUP_THRESHOLD = 1 << 30; private final UUID _id; private ConnectionConfig _connectionConfig; private long _createTime = System.currentTimeMillis(); private LogActor _actor = GenericActor.getInstance(this); + private PostEnqueueAction _postEnqueueAction = new PostEnqueueAction(); + + private final ConcurrentMap<AMQQueue, Boolean> _blockingQueues = new ConcurrentHashMap<AMQQueue, Boolean>(); + + private final AtomicBoolean _blocking = new AtomicBoolean(false); + private ChannelLogSubject _logSubject; + private final AtomicInteger _outstandingCredit = new AtomicInteger(UNLIMITED_CREDIT); + public static interface MessageDispositionChangeListener { @@ -121,8 +138,6 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi private final List<Task> _taskList = new CopyOnWriteArrayList<Task>(); - private final WeakReference<Session> _reference; - ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry) { this(connection, delegate, name, expiry, ((ServerConnection)connection).getConfig()); @@ -133,8 +148,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi super(connection, delegate, name, expiry); _connectionConfig = connConfig; _transaction = new AutoCommitTransaction(this.getMessageStore()); - - _reference = new WeakReference<Session>(this); + _logSubject = new ChannelLogSubject(this); _id = getConfigStore().createId(); getConfigStore().addConfiguredObject(this); } @@ -161,40 +175,28 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi return isCommandsFull(id); } - public void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues) + public void enqueue(final ServerMessage message, final List<? extends BaseQueue> queues) { + if(_outstandingCredit.get() != UNLIMITED_CREDIT + && _outstandingCredit.decrementAndGet() == (Integer.MAX_VALUE - PRODUCER_CREDIT_TOPUP_THRESHOLD)) + { + _outstandingCredit.addAndGet(PRODUCER_CREDIT_TOPUP_THRESHOLD); + invoke(new MessageFlow("",MessageCreditUnit.MESSAGE, PRODUCER_CREDIT_TOPUP_THRESHOLD)); + } getConnectionModel().registerMessageReceived(message.getSize(), message.getArrivalTime()); - _transaction.enqueue(queues,message, new ServerTransaction.Action() - { - - BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]); - - public void postCommit() - { - MessageReference<?> ref = message.newReference(); - for(int i = 0; i < _queues.length; i++) - { - try - { - _queues[i].enqueue(message); - } - catch (AMQException e) - { - // TODO - throw new RuntimeException(e); - } - } - ref.release(); - } - - public void onRollback() - { - // NO-OP - } - }); - - incrementOutstandingTxnsIfNecessary(); - updateTransactionalActivity(); + PostEnqueueAction postTransactionAction; + if(isTransactional()) + { + postTransactionAction = new PostEnqueueAction(queues, message) ; + } + else + { + postTransactionAction = _postEnqueueAction; + postTransactionAction.setState(queues, message); + } + _transaction.enqueue(queues,message, postTransactionAction, 0L); + incrementOutstandingTxnsIfNecessary(); + updateTransactionalActivity(); } @@ -252,7 +254,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi public RangeSet acquire(RangeSet transfers) { - RangeSet acquired = new RangeSet(); + RangeSet acquired = RangeSetFactory.createRangeSet(); if(!_messageDispositionListenerMap.isEmpty()) { @@ -300,41 +302,56 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi public void dispositionChange(RangeSet ranges, MessageDispositionAction action) { - if(ranges != null && !_messageDispositionListenerMap.isEmpty()) + if(ranges != null) { - Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); - Iterator<Range> rangeIter = ranges.iterator(); - if(rangeIter.hasNext()) + if(ranges.size() == 1) { - Range range = rangeIter.next(); + Range r = ranges.getFirst(); + for(int i = r.getLower(); i <= r.getUpper(); i++) + { + MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(i); + if(changeListener != null) + { + action.performAction(changeListener); + } + } + } + else if(!_messageDispositionListenerMap.isEmpty()) + { + Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator(); + Iterator<Range> rangeIter = ranges.iterator(); - while(range != null && unacceptedMessages.hasNext()) + if(rangeIter.hasNext()) { - int next = unacceptedMessages.next(); - while(gt(next, range.getUpper())) + Range range = rangeIter.next(); + + while(range != null && unacceptedMessages.hasNext()) { - if(rangeIter.hasNext()) + int next = unacceptedMessages.next(); + while(gt(next, range.getUpper())) { - range = rangeIter.next(); + if(rangeIter.hasNext()) + { + range = rangeIter.next(); + } + else + { + range = null; + break; + } } - else + if(range != null && range.includes(next)) { - range = null; - break; + MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next); + action.performAction(changeListener); } - } - if(range != null && range.includes(next)) - { - MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next); - action.performAction(changeListener); - } - } + } + } } - } } @@ -534,10 +551,10 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi _taskList.remove(task); } - public WeakReference<Session> getReference() - { - return _reference; - } + public Object getReference() + { + return ((ServerConnection) getConnection()).getReference(); + } public MessageStore getMessageStore() { @@ -666,13 +683,57 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi } } + public void block(AMQQueue queue) + { + if(_blockingQueues.putIfAbsent(queue, Boolean.TRUE) == null) + { + + if(_blocking.compareAndSet(false,true)) + { + invoke(new MessageSetFlowMode("", MessageFlowMode.CREDIT)); + invoke(new MessageStop("")); + _actor.message(_logSubject, ChannelMessages.FLOW_ENFORCED(queue.getNameShortString().toString())); + } + + + } + } + + public void unblock(AMQQueue queue) + { + if(_blockingQueues.remove(queue) && _blockingQueues.isEmpty()) + { + if(_blocking.compareAndSet(true,false)) + { + + _actor.message(_logSubject, ChannelMessages.FLOW_REMOVED()); + MessageFlow mf = new MessageFlow(); + mf.setUnit(MessageCreditUnit.MESSAGE); + mf.setDestination(""); + _outstandingCredit.set(Integer.MAX_VALUE); + mf.setValue(Integer.MAX_VALUE); + invoke(mf); + + + } + } + } + + public String toLogString() { - return "[" + + long connectionId = getConnection() instanceof ServerConnection + ? ((ServerConnection) getConnection()).getConnectionId() + : -1; + + String remoteAddress = _connectionConfig instanceof ProtocolEngine + ? ((ProtocolEngine) _connectionConfig).getRemoteAddress().toString() + : ""; + return "[" + MessageFormat.format(CHANNEL_FORMAT, - ((ServerConnection) getConnection()).getConnectionId(), + connectionId, getClientID(), - ((ProtocolEngine) _connectionConfig).getRemoteAddress().toString(), + remoteAddress, getVirtualHost().getName(), getChannel()) + "] "; @@ -697,7 +758,7 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi } } - public void flushCreditState() + public void receivedComplete() { final Collection<Subscription_0_10> subscriptions = getSubscriptions(); for (Subscription_0_10 subscription_0_10 : subscriptions) @@ -706,6 +767,60 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi } } + private class PostEnqueueAction implements ServerTransaction.Action + { + + private List<? extends BaseQueue> _queues; + private ServerMessage _message; + private final boolean _transactional; + + public PostEnqueueAction(List<? extends BaseQueue> queues, ServerMessage message) + { + _transactional = true; + setState(queues, message); + } + + public PostEnqueueAction() + { + _transactional = false; + } + + public void setState(List<? extends BaseQueue> queues, ServerMessage message) + { + _message = message; + _queues = queues; + } + + public void postCommit() + { + MessageReference<?> ref = _message.newReference(); + for(int i = 0; i < _queues.size(); i++) + { + try + { + BaseQueue queue = _queues.get(i); + queue.enqueue(_message, _transactional, null); + if(queue instanceof AMQQueue) + { + ((AMQQueue)queue).checkCapacity(ServerSession.this); + } + + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + } + ref.release(); + } + + public void onRollback() + { + // NO-OP + } + } + public int getUnacknowledgedMessageCount() { return _messageDispositionListenerMap.size(); @@ -713,6 +828,6 @@ public class ServerSession extends Session implements AuthorizationHolder, Sessi public boolean getBlocking() { - return false; //TODO: Blocking not implemented on 0-10 yet. + return _blocking.get(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index a0dca53ed0..b6e142a5fd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.transport; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; import org.apache.log4j.Logger; @@ -55,46 +56,7 @@ import org.apache.qpid.server.store.StoredMessage; import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; import org.apache.qpid.server.subscription.Subscription_0_10; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.transport.Acquired; -import org.apache.qpid.transport.DeliveryProperties; -import org.apache.qpid.transport.ExchangeBind; -import org.apache.qpid.transport.ExchangeBound; -import org.apache.qpid.transport.ExchangeBoundResult; -import org.apache.qpid.transport.ExchangeDeclare; -import org.apache.qpid.transport.ExchangeDelete; -import org.apache.qpid.transport.ExchangeQuery; -import org.apache.qpid.transport.ExchangeQueryResult; -import org.apache.qpid.transport.ExchangeUnbind; -import org.apache.qpid.transport.ExecutionErrorCode; -import org.apache.qpid.transport.ExecutionException; -import org.apache.qpid.transport.MessageAccept; -import org.apache.qpid.transport.MessageAcceptMode; -import org.apache.qpid.transport.MessageAcquire; -import org.apache.qpid.transport.MessageAcquireMode; -import org.apache.qpid.transport.MessageCancel; -import org.apache.qpid.transport.MessageFlow; -import org.apache.qpid.transport.MessageFlowMode; -import org.apache.qpid.transport.MessageFlush; -import org.apache.qpid.transport.MessageReject; -import org.apache.qpid.transport.MessageRejectCode; -import org.apache.qpid.transport.MessageRelease; -import org.apache.qpid.transport.MessageResume; -import org.apache.qpid.transport.MessageSetFlowMode; -import org.apache.qpid.transport.MessageStop; -import org.apache.qpid.transport.MessageSubscribe; -import org.apache.qpid.transport.MessageTransfer; -import org.apache.qpid.transport.Method; -import org.apache.qpid.transport.QueueDeclare; -import org.apache.qpid.transport.QueueDelete; -import org.apache.qpid.transport.QueuePurge; -import org.apache.qpid.transport.QueueQuery; -import org.apache.qpid.transport.QueueQueryResult; -import org.apache.qpid.transport.RangeSet; -import org.apache.qpid.transport.Session; -import org.apache.qpid.transport.SessionDelegate; -import org.apache.qpid.transport.TxCommit; -import org.apache.qpid.transport.TxRollback; -import org.apache.qpid.transport.TxSelect; +import org.apache.qpid.transport.*; public class ServerSessionDelegate extends SessionDelegate { @@ -295,7 +257,8 @@ public class ServerSessionDelegate extends SessionDelegate final Exchange exchange = getExchangeForMessage(ssn, xfr); DeliveryProperties delvProps = null; - if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration()) + if(xfr.getHeader() != null && (delvProps = xfr.getHeader().getDeliveryProperties()) != null && delvProps.hasTtl() && !delvProps + .hasExpiration()) { delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl()); } @@ -312,7 +275,7 @@ public class ServerSessionDelegate extends SessionDelegate } final Exchange exchangeInUse; - ArrayList<? extends BaseQueue> queues = exchange.route(messageMetaData); + List<? extends BaseQueue> queues = exchange.route(messageMetaData); if(queues.isEmpty() && exchange.getAlternateExchange() != null) { final Exchange alternateExchange = exchange.getAlternateExchange(); @@ -334,15 +297,16 @@ public class ServerSessionDelegate extends SessionDelegate if(!queues.isEmpty()) { final MessageStore store = getVirtualHost(ssn).getMessageStore(); - final StoredMessage<MessageMetaData_0_10> storeMessage = createAndFlushStoreMessage(xfr, messageMetaData, store); + final StoredMessage<MessageMetaData_0_10> storeMessage = createStoreMessage(xfr, messageMetaData, store); MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference()); ((ServerSession) ssn).enqueue(message, queues); + storeMessage.flushToStore(); } else { if((delvProps == null || !delvProps.getDiscardUnroutable()) && xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT) { - RangeSet rejects = new RangeSet(); + RangeSet rejects = RangeSetFactory.createRangeSet(); rejects.add(xfr.getId()); MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable"); ssn.invoke(reject); @@ -353,11 +317,13 @@ public class ServerSessionDelegate extends SessionDelegate } } + + ssn.processed(xfr); } - private StoredMessage<MessageMetaData_0_10> createAndFlushStoreMessage(final MessageTransfer xfr, - final MessageMetaData_0_10 messageMetaData, final MessageStore store) + private StoredMessage<MessageMetaData_0_10> createStoreMessage(final MessageTransfer xfr, + final MessageMetaData_0_10 messageMetaData, final MessageStore store) { final StoredMessage<MessageMetaData_0_10> storeMessage = store.addMessage(messageMetaData); ByteBuffer body = xfr.getBody(); @@ -365,7 +331,6 @@ public class ServerSessionDelegate extends SessionDelegate { storeMessage.addContent(0, body); } - storeMessage.flushToStore(); return storeMessage; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java index 36e9d78440..a67d4badd1 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.txn; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -30,7 +31,7 @@ import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.MessageStore; /** * An implementation of ServerTransaction where each enqueue/dequeue @@ -43,11 +44,11 @@ public class AutoCommitTransaction implements ServerTransaction { protected static final Logger _logger = Logger.getLogger(AutoCommitTransaction.class); - private final TransactionLog _transactionLog; + private final MessageStore _messageStore; - public AutoCommitTransaction(TransactionLog transactionLog) + public AutoCommitTransaction(MessageStore transactionLog) { - _transactionLog = transactionLog; + _messageStore = transactionLog; } public long getTransactionStartTime() @@ -59,14 +60,14 @@ public class AutoCommitTransaction implements ServerTransaction * Since AutoCommitTransaction have no concept of a long lived transaction, any Actions registered * by the caller are executed immediately. */ - public void addPostTransactionAction(Action immediateAction) + public void addPostTransactionAction(final Action immediateAction) { immediateAction.postCommit(); } public void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction) { - TransactionLog.Transaction txn = null; + MessageStore.Transaction txn = null; try { if(message.isPersistent() && queue.isDurable()) @@ -76,8 +77,8 @@ public class AutoCommitTransaction implements ServerTransaction _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString()); } - txn = _transactionLog.newTransaction(); - txn.dequeueMessage(queue, message.getMessageNumber()); + txn = _messageStore.newTransaction(); + txn.dequeueMessage(queue, message); txn.commitTran(); txn = null; } @@ -98,7 +99,7 @@ public class AutoCommitTransaction implements ServerTransaction public void dequeue(Collection<QueueEntry> queueEntries, Action postTransactionAction) { - TransactionLog.Transaction txn = null; + MessageStore.Transaction txn = null; try { for(QueueEntry entry : queueEntries) @@ -115,10 +116,10 @@ public class AutoCommitTransaction implements ServerTransaction if(txn == null) { - txn = _transactionLog.newTransaction(); + txn = _messageStore.newTransaction(); } - txn.dequeueMessage(queue, message.getMessageNumber()); + txn.dequeueMessage(queue, message); } } @@ -145,7 +146,7 @@ public class AutoCommitTransaction implements ServerTransaction public void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction) { - TransactionLog.Transaction txn = null; + MessageStore.Transaction txn = null; try { if(message.isPersistent() && queue.isDurable()) @@ -155,8 +156,8 @@ public class AutoCommitTransaction implements ServerTransaction _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString()); } - txn = _transactionLog.newTransaction(); - txn.enqueueMessage(queue, message.getMessageNumber()); + txn = _messageStore.newTransaction(); + txn.enqueueMessage(queue, message); txn.commitTran(); txn = null; } @@ -176,15 +177,14 @@ public class AutoCommitTransaction implements ServerTransaction } - public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction) + public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction, long currentTime) { - TransactionLog.Transaction txn = null; + MessageStore.Transaction txn = null; try { if(message.isPersistent()) { - Long id = message.getMessageNumber(); for(BaseQueue queue : queues) { if (queue.isDurable()) @@ -195,22 +195,26 @@ public class AutoCommitTransaction implements ServerTransaction } if (txn == null) { - txn = _transactionLog.newTransaction(); + txn = _messageStore.newTransaction(); } - txn.enqueueMessage(queue, id); + txn.enqueueMessage(queue, message); + + } } - if (txn != null) - { - txn.commitTran(); - txn = null; - - } } + if (txn != null) + { + txn.commitTran(); + txn = null; + } + postTransactionAction.postCommit(); postTransactionAction = null; + + } catch (AMQException e) { @@ -225,6 +229,11 @@ public class AutoCommitTransaction implements ServerTransaction } + public void commit(final Runnable immediatePostTransactionAction) + { + immediatePostTransactionAction.run(); + } + public void commit() { } @@ -233,7 +242,7 @@ public class AutoCommitTransaction implements ServerTransaction { } - private void rollbackIfNecessary(Action postTransactionAction, TransactionLog.Transaction txn) + private void rollbackIfNecessary(Action postTransactionAction, MessageStore.Transaction txn) { if (txn != null) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java index 946dbd7c28..7f5b5fb8b2 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java @@ -29,11 +29,7 @@ import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.BaseQueue; -import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.MessageStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,11 +46,11 @@ public class LocalTransaction implements ServerTransaction private final List<Action> _postTransactionActions = new ArrayList<Action>(); - private volatile TransactionLog.Transaction _transaction; - private TransactionLog _transactionLog; + private volatile MessageStore.Transaction _transaction; + private MessageStore _transactionLog; private long _txnStartTime = 0L; - public LocalTransaction(TransactionLog transactionLog) + public LocalTransaction(MessageStore transactionLog) { _transactionLog = transactionLog; } @@ -63,7 +59,7 @@ public class LocalTransaction implements ServerTransaction { return _transaction != null; } - + public long getTransactionStartTime() { return _txnStartTime; @@ -88,7 +84,7 @@ public class LocalTransaction implements ServerTransaction } beginTranIfNecessary(); - _transaction.dequeueMessage(queue, message.getMessageNumber()); + _transaction.dequeueMessage(queue, message); } catch(AMQException e) @@ -118,7 +114,7 @@ public class LocalTransaction implements ServerTransaction } beginTranIfNecessary(); - _transaction.dequeueMessage(queue, message.getMessageNumber()); + _transaction.dequeueMessage(queue, message); } } @@ -191,7 +187,7 @@ public class LocalTransaction implements ServerTransaction } beginTranIfNecessary(); - _transaction.enqueueMessage(queue, message.getMessageNumber()); + _transaction.enqueueMessage(queue, message); } catch (Exception e) { @@ -202,13 +198,13 @@ public class LocalTransaction implements ServerTransaction } } - public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction) + public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction, long currentTime) { _postTransactionActions.add(postTransactionAction); if (_txnStartTime == 0L) { - _txnStartTime = System.currentTimeMillis(); + _txnStartTime = currentTime == 0L ? System.currentTimeMillis() : currentTime; } if(message.isPersistent()) @@ -226,7 +222,7 @@ public class LocalTransaction implements ServerTransaction beginTranIfNecessary(); - _transaction.enqueueMessage(queue, message.getMessageNumber()); + _transaction.enqueueMessage(queue, message); } } @@ -242,6 +238,11 @@ public class LocalTransaction implements ServerTransaction public void commit() { + commit(null); + } + + public void commit(Runnable immediateAction) + { try { if(_transaction != null) @@ -249,9 +250,14 @@ public class LocalTransaction implements ServerTransaction _transaction.commitTran(); } - for(Action action : _postTransactionActions) + if(immediateAction != null) + { + immediateAction.run(); + } + + for(int i = 0; i < _postTransactionActions.size(); i++) { - action.postCommit(); + _postTransactionActions.get(i).postCommit(); } } catch (Exception e) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java index b3c6e1ac3a..acdf712de9 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.txn; +import java.util.Collection; +import java.util.List; import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueEntry; -import java.util.Collection; -import java.util.List; - /** * The ServerTransaction interface allows a set enqueue/dequeue operations to be @@ -42,7 +41,7 @@ import java.util.List; */ public interface ServerTransaction { - /** + /** * Represents an action to be performed on transaction commit or rollback */ public static interface Action @@ -91,7 +90,7 @@ public interface ServerTransaction * * Store operations will result only for a persistent messages on durable queues. */ - void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction); + void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction, long currentTime); /** * Commit the transaction represented by this object. @@ -101,6 +100,8 @@ public interface ServerTransaction */ void commit(); + void commit(Runnable immediatePostTransactionAction); + /** Rollback the transaction represented by this object. * * If the caller has registered one or more Actions, the onRollback() method on each will 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 e8042fcaaf..41a5471a64 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.Map; import java.util.UUID; import org.apache.qpid.common.Closeable; @@ -40,7 +41,6 @@ import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.stats.StatisticsGatherer; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.TransactionLog; public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable, StatisticsGatherer { @@ -58,8 +58,6 @@ public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHo MessageStore getMessageStore(); - TransactionLog getTransactionLog(); - DurableConfigurationStore getDurableConfigurationStore(); AuthenticationManager getAuthenticationManager(); @@ -95,6 +93,8 @@ public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHo boolean durable, String authMechanism, String username, String password); + public BrokerLink createBrokerConnection(UUID id, long createTime, Map<String,String> arguments); + ConfigStore getConfigStore(); void removeBrokerConnection(BrokerLink brokerLink); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 0fd31973b2..51892d965a 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -20,12 +20,13 @@ */ package org.apache.qpid.server.virtualhost; +import org.apache.qpid.server.federation.BrokerLink; +import org.apache.qpid.server.message.EnqueableMessage; 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; @@ -43,7 +44,7 @@ import org.apache.qpid.framing.FieldTable; import org.apache.qpid.AMQException; import org.apache.log4j.Logger; -import org.apache.qpid.server.util.ByteBufferInputStream; +import org.apache.qpid.util.ByteBufferInputStream; import java.io.DataInputStream; import java.io.IOException; @@ -54,11 +55,13 @@ import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.TreeMap; +import java.util.UUID; public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHandler, ConfigurationRecoveryHandler.QueueRecoveryHandler, ConfigurationRecoveryHandler.ExchangeRecoveryHandler, ConfigurationRecoveryHandler.BindingRecoveryHandler, + ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler, MessageStoreRecoveryHandler, MessageStoreRecoveryHandler.StoredMessageRecoveryHandler, TransactionLogRecoveryHandler, @@ -73,7 +76,6 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa 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>(); @@ -86,7 +88,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa _virtualHost = virtualHost; } - public QueueRecoveryHandler begin(MessageStore store) + public VirtualHostConfigRecoveryHandler begin(MessageStore store) { _logSubject = new MessageStoreLogSubject(_virtualHost,store); _store = store; @@ -99,14 +101,12 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa { try { - AMQShortString queueNameShortString = new AMQShortString(queueName); - - AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString); + AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueName); if (q == null) { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, exclusive, _virtualHost, - arguments); + q = AMQQueueFactory.createAMQQueueImpl(queueName, true, owner, false, exclusive, _virtualHost, + FieldTable.convertToMap(arguments)); _virtualHost.getQueueRegistry().registerQueue(q); } @@ -183,13 +183,19 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa public void completeMessageRecovery() { //TODO - log end - //To change body of implemented methods use File | Settings | File Templates. } - public TransactionLogRecoveryHandler.QueueEntryRecoveryHandler begin(TransactionLog log) + public BridgeRecoveryHandler brokerLink(final UUID id, + final long createTime, + final Map<String, String> arguments) + { + BrokerLink blink = _virtualHost.createBrokerConnection(id, createTime, arguments); + return new BridgeRecoveryHandlerImpl(blink); + + } + + public void completeBrokerLinkRecovery() { - _transactionLog = log; - return this; } private static final class ProcessAction @@ -270,9 +276,9 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa } - public void completeBindingRecovery() + public BrokerLinkRecoveryHandler completeBindingRecovery() { - //return this; + return this; } public void complete() @@ -316,15 +322,15 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa else { _logger.warn("Message id " + messageId + " referenced in log as enqueued in queue " + queue.getNameShortString() + " is unknown, entry will be discarded"); - TransactionLog.Transaction txn = _transactionLog.newTransaction(); - txn.dequeueMessage(queue, messageId); + MessageStore.Transaction txn = _store.newTransaction(); + txn.dequeueMessage(queue, new DummyMessage(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(); + MessageStore.Transaction txn = _store.newTransaction(); TransactionLogResource mockQueue = new TransactionLogResource() { @@ -334,7 +340,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa return queueName; } }; - txn.dequeueMessage(mockQueue, messageId); + txn.dequeueMessage(mockQueue, new DummyMessage(messageId)); txn.commitTranAsync(); } @@ -367,4 +373,51 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_COMPLETE(null, false)); } + private static class DummyMessage implements EnqueableMessage + { + + + private final long _messageId; + + public DummyMessage(long messageId) + { + _messageId = messageId; + } + + public long getMessageNumber() + { + return _messageId; + } + + + public boolean isPersistent() + { + return true; + } + + + public StoredMessage getStoredMessage() + { + return null; + } + } + + private class BridgeRecoveryHandlerImpl implements BridgeRecoveryHandler + { + private final BrokerLink _blink; + + public BridgeRecoveryHandlerImpl(final BrokerLink blink) + { + _blink = blink; + } + + public void bridge(final UUID id, final long createTime, final Map<String, String> arguments) + { + _blink.createBridge(id, createTime, arguments); + } + + public void completeBridgeRecoveryForLink() + { + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index fde758203b..a4a3633af7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -55,6 +55,7 @@ import org.apache.qpid.server.exchange.DefaultExchangeRegistry; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.federation.Bridge; import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; @@ -77,7 +78,6 @@ import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.TransactionLog; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; @@ -231,7 +231,10 @@ public class VirtualHostImpl implements VirtualHost if (store != null) { _messageStore = store; - _durableConfigurationStore = store; + if(store instanceof DurableConfigurationStore) + { + _durableConfigurationStore = (DurableConfigurationStore) store; + } } else { @@ -383,6 +386,8 @@ public class VirtualHostImpl implements VirtualHost 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 + @@ -393,10 +398,18 @@ public class VirtualHostImpl implements VirtualHost MessageStoreLogSubject storeLogSubject = new MessageStoreLogSubject(this, messageStore); - messageStore.configureConfigStore(this.getName(), - recoveryHandler, - hostConfig.getStoreConfiguration(), - storeLogSubject); + + if(messageStore instanceof DurableConfigurationStore) + { + DurableConfigurationStore durableConfigurationStore = (DurableConfigurationStore) messageStore; + + durableConfigurationStore.configureConfigStore(this.getName(), + recoveryHandler, + hostConfig.getStoreConfiguration(), + storeLogSubject); + + _durableConfigurationStore = durableConfigurationStore; + } messageStore.configureMessageStore(this.getName(), recoveryHandler, @@ -408,7 +421,8 @@ public class VirtualHostImpl implements VirtualHost storeLogSubject); _messageStore = messageStore; - _durableConfigurationStore = messageStore; + + } private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException @@ -556,11 +570,6 @@ public class VirtualHostImpl implements VirtualHost return _messageStore; } - public TransactionLog getTransactionLog() - { - return _messageStore; - } - public DurableConfigurationStore getDurableConfigurationStore() { return _durableConfigurationStore; @@ -725,6 +734,16 @@ public class VirtualHostImpl implements VirtualHost _statisticsEnabled = enabled; } + public BrokerLink createBrokerConnection(UUID id, long createTime, Map<String,String> arguments) + { + BrokerLink blink = new BrokerLink(this, id, createTime, arguments); + // TODO - cope with duplicate broker link creation requests + _links.putIfAbsent(blink,blink); + getConfigStore().addConfiguredObject(blink); + return blink; + } + + public void createBrokerConnection(final String transport, final String host, final int port, @@ -735,10 +754,11 @@ public class VirtualHostImpl implements VirtualHost final String password) { BrokerLink blink = new BrokerLink(this, transport, host, port, vhost, durable, authMechanism, username, password); - if(_links.putIfAbsent(blink,blink) != null) - { - getConfigStore().addConfiguredObject(blink); - } + + // TODO - cope with duplicate broker link creation requests + _links.putIfAbsent(blink,blink); + getConfigStore().addConfiguredObject(blink); + } public void removeBrokerConnection(final String transport, @@ -788,7 +808,9 @@ public class VirtualHostImpl implements VirtualHost public List<Exchange> exchange = new LinkedList<Exchange>(); public List<CreateQueueTuple> queue = new LinkedList<CreateQueueTuple>(); public List<CreateBindingTuple> bindings = new LinkedList<CreateBindingTuple>(); - + public List<BrokerLink> links = new LinkedList<BrokerLink>(); + public List<Bridge> bridges = new LinkedList<Bridge>(); + public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception { } @@ -883,6 +905,30 @@ public class VirtualHostImpl implements VirtualHost public void updateQueue(AMQQueue queue) throws AMQStoreException { } + + public void createBrokerLink(final BrokerLink link) throws AMQStoreException + { + if(link.isDurable()) + { + links.add(link); + } + } + + public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException + { + } + + public void createBridge(final Bridge bridge) throws AMQStoreException + { + if(bridge.isDurable()) + { + bridges.add(bridge); + } + } + + public void deleteBridge(final Bridge bridge) throws AMQStoreException + { + } } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java index bfcdbe7460..3d3c7b6cc6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java @@ -20,15 +20,13 @@ */ package org.apache.qpid.tools.security; -import org.apache.commons.codec.binary.Base64; - +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.DigestException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintStream; +import org.apache.commons.codec.binary.Base64; public class Passwd { @@ -40,7 +38,14 @@ public class Passwd System.exit(0); } - byte[] data = args[1].getBytes("utf-8"); + Passwd passwd = new Passwd(); + String output = passwd.getOutput(args[0], args[1]); + System.out.println(output); + } + + public String getOutput(String userName, String password) throws UnsupportedEncodingException, NoSuchAlgorithmException + { + byte[] data = password.getBytes("utf-8"); MessageDigest md = MessageDigest.getInstance("MD5"); @@ -55,24 +60,8 @@ public class Passwd byte[] encoded = b64.encode(digest); - output(args[0], encoded); + String encodedStr = new String(encoded, Charset.forName("utf-8")); + return userName + ":" + encodedStr; } - private static void output(String user, byte[] encoded) throws IOException - { - PrintStream ps = new PrintStream(System.out); - - user += ":"; - ps.write(user.getBytes("utf-8")); - - for (byte b : encoded) - { - ps.write(b); - } - - ps.println(); - - ps.flush(); - ps.close(); - } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java index eea8e173f4..3e4c30291c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java @@ -165,6 +165,11 @@ public class MainTest extends QpidTestCase _options = options; } + @Override + protected void setExceptionHandler() + { + } + public BrokerOptions getOptions() { return _options; 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 7739f9976e..eb4a90d9f3 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 @@ -600,19 +600,6 @@ public class ServerConfigurationTest extends QpidTestCase assertEquals("a", _serverConfig.getConnectorCertType()); } - public void testGetUseBiasedWrites() throws ConfigurationException - { - // Check default - _serverConfig.initialise(); - assertEquals(false, _serverConfig.getUseBiasedWrites()); - - // Check value we set - _config.setProperty("advanced.useWriteBiasedPool", true); - _serverConfig = new ServerConfiguration(_config); - _serverConfig.initialise(); - assertEquals(true, _serverConfig.getUseBiasedWrites()); - } - public void testGetHousekeepingCheckPeriod() throws ConfigurationException { // Check default 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 a0a29cf734..7bd711a19c 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 @@ -72,7 +72,7 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase /** * Not used in this test, just there to stub out the routing calls */ - private MessageStore _store = new MemoryMessageStore(); + private MemoryMessageStore _store = new MemoryMessageStore(); BindingFactory bindingFactory = new BindingFactory(new DurableConfigurationStore.Source() @@ -310,7 +310,7 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase * @throws AMQException */ @Override - public void enqueue(ServerMessage msg, PostEnqueueAction action) throws AMQException + public void enqueue(ServerMessage msg, boolean sync, PostEnqueueAction action) throws AMQException { messages.add( new HeadersExchangeTest.Message((AMQMessage) msg)); final QueueEntry queueEntry = new QueueEntry() @@ -318,47 +318,47 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase public AMQQueue getQueue() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public AMQMessage getMessage() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public long getSize() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public boolean getDeliveredToConsumer() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean expired() throws AMQException { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean isAvailable() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean isAcquired() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean acquire() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean acquire(Subscription sub) { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean delete() @@ -373,17 +373,17 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase public boolean acquiredBySubscription() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean isAcquiredBy(Subscription subscription) { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public void release() { - //To change body of implemented methods use File | Settings | File Templates. + } public boolean releaseButRetain() @@ -393,42 +393,42 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase public boolean immediateAndNotDelivered() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } 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. + return null; } public boolean isPersistent() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean isRedelivered() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public Subscription getDeliveredSubscription() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public void reject() { - //To change body of implemented methods use File | Settings | File Templates. + } public boolean isRejectedBy(long subscriptionId) { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public void requeue(Subscription subscription) @@ -438,42 +438,42 @@ public class AbstractHeadersExchangeTestBase extends InternalBrokerBaseCase public void dequeue() { - //To change body of implemented methods use File | Settings | File Templates. + } public void dispose() { - //To change body of implemented methods use File | Settings | File Templates. + } 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. + } public boolean isQueueDeleted() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public void addStateChangeListener(StateChangeListener listener) { - //To change body of implemented methods use File | Settings | File Templates. + } public boolean removeStateChangeListener(StateChangeListener listener) { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public int compareTo(final QueueEntry o) { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public boolean isDequeued() diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java index 32ad1d110d..9a065ea2db 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.logging.actors; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.AMQException; import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.logging.NullRootMessageLogger; /** @@ -49,10 +50,7 @@ import org.apache.qpid.server.logging.NullRootMessageLogger; public class CurrentActorTest extends BaseConnectionActorTestCase { //Set this to be a reasonably large number - int THREADS = 10; - - // Record any exceptions that are thrown by the threads - Exception[] _errors = new Exception[THREADS]; + private static final int THREADS = 10; /** * Test that CurrentActor behaves as LIFO queue. @@ -161,19 +159,11 @@ public class CurrentActorTest extends BaseConnectionActorTestCase public void testThreadLocal() { - new Runnable(){ - public void run() - { - System.out.println(_errors[0]); - } - }; - // Setup the threads - Thread[] threads = new Thread[THREADS]; + LogMessagesWithAConnectionActor[] threads = new LogMessagesWithAConnectionActor[THREADS]; for (int count = 0; count < THREADS; count++) { - Runnable test = new LogMessagesWithAConnectionActor(count); - threads[count] = new Thread(test); + threads[count] = new LogMessagesWithAConnectionActor(); } //Run the threads @@ -198,10 +188,10 @@ public class CurrentActorTest extends BaseConnectionActorTestCase // Verify that none of the tests threw an exception for (int count = 0; count < THREADS; count++) { - if (_errors[count] != null) + if (threads[count].getException() != null) { - _errors[count].printStackTrace(); - fail("Error occured in thread:" + count); + threads[count].getException().printStackTrace(); + fail("Error occured in thread:" + count + "("+threads[count].getException()+")"); } } } @@ -210,13 +200,12 @@ public class CurrentActorTest extends BaseConnectionActorTestCase * Creates a new ConnectionActor and logs the given number of messages * before removing the actor and validating that there is no set actor. */ - public class LogMessagesWithAConnectionActor implements Runnable + public class LogMessagesWithAConnectionActor extends Thread { - int count; + Throwable _exception; - LogMessagesWithAConnectionActor(int count) + public LogMessagesWithAConnectionActor() { - this.count = count; } public void run() @@ -227,6 +216,7 @@ public class CurrentActorTest extends BaseConnectionActorTestCase //fixme reminder that we need a better approach for broker testing. try { + LogActor defaultActor = CurrentActor.get(); AMQPConnectionActor actor = new AMQPConnectionActor(getSession(), new NullRootMessageLogger()); @@ -237,20 +227,26 @@ public class CurrentActorTest extends BaseConnectionActorTestCase sendTestLogMessage(CurrentActor.get()); // Verify it was the same actor as we set earlier - assertEquals("Retrieved actor is not as expected ", - actor, CurrentActor.get()); + if(!actor.equals(CurrentActor.get())) + throw new IllegalArgumentException("Retrieved actor is not as expected "); // Verify that removing the actor works for this thread CurrentActor.remove(); - assertNull("CurrentActor should be null", CurrentActor.get()); + if(CurrentActor.get() != defaultActor) + throw new IllegalArgumentException("CurrentActor ("+CurrentActor.get()+") should be default actor" + defaultActor); } - catch (Exception e) + catch (Throwable e) { - _errors[count] = e; + _exception = e; } } + + public Throwable getException() + { + return _exception; + } } } 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 2ce43052d9..d5f8ef3d54 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 @@ -64,17 +64,17 @@ public class AMQPriorityQueueTest extends SimpleAMQQueueTest ArrayList<QueueEntry> msgs = _subscription.getMessages(); try { - 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(1L, msgs.get(0).getMessage().getMessageNumber()); + assertEquals(6L, msgs.get(1).getMessage().getMessageNumber()); + assertEquals(8L, msgs.get(2).getMessage().getMessageNumber()); - 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(2L, msgs.get(3).getMessage().getMessageNumber()); + assertEquals(5L, msgs.get(4).getMessage().getMessageNumber()); + assertEquals(7L, msgs.get(5).getMessage().getMessageNumber()); - 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()); + assertEquals(3L, msgs.get(6).getMessage().getMessageNumber()); + assertEquals(4L, msgs.get(7).getMessage().getMessageNumber()); + assertEquals(9L, msgs.get(8).getMessage().getMessageNumber()); } catch (AssertionFailedError afe) { 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 0daf79122c..f97ac5659e 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 @@ -30,7 +30,6 @@ import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.security.AuthorizationHolder; -import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.txn.ServerTransaction; @@ -168,22 +167,22 @@ public class MockAMQQueue implements AMQQueue public UUID getId() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public QueueConfigType getConfigType() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public ConfiguredObject getParent() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public boolean isDurable() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean isAutoDelete() @@ -199,7 +198,7 @@ public class MockAMQQueue implements AMQQueue public AMQShortString getOwner() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public void setVirtualHost(VirtualHost virtualhost) @@ -219,22 +218,22 @@ public class MockAMQQueue implements AMQQueue public void registerSubscription(Subscription subscription, boolean exclusive) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + } public void unregisterSubscription(Subscription subscription) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + } public int getConsumerCount() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public int getActiveConsumerCount() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public boolean hasExclusiveSubscriber() @@ -244,37 +243,37 @@ public class MockAMQQueue implements AMQQueue public boolean isUnused() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public boolean isEmpty() { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public int getMessageCount() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public int getUndeliveredMessageCount() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public long getQueueDepth() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public long getReceivedMessageCount() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public long getOldestMessageArrivalTime() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public boolean isDeleted() @@ -297,59 +296,58 @@ public class MockAMQQueue implements AMQQueue } + public void enqueue(ServerMessage message, boolean sync, PostEnqueueAction action) throws AMQException + { + } + public void requeue(QueueEntry entry) { - //To change body of implemented methods use File | Settings | File Templates. } public void requeue(QueueEntryImpl storeContext, Subscription subscription) { - //To change body of implemented methods use File | Settings | File Templates. } public void dequeue(QueueEntry entry, Subscription sub) { - //To change body of implemented methods use File | Settings | File Templates. } public boolean resend(QueueEntry entry, Subscription subscription) throws AMQException { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } public void addQueueDeleteTask(Task task) { - //To change body of implemented methods use File | Settings | File Templates. } public void removeQueueDeleteTask(final Task task) { - //To change body of implemented methods use File | Settings | File Templates. } public List<QueueEntry> getMessagesOnTheQueue() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public List<QueueEntry> getMessagesOnTheQueue(long fromMessageId, long toMessageId) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public List<Long> getMessagesOnTheQueue(int num) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public List<Long> getMessagesOnTheQueue(int num, int offest) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public QueueEntry getMessageOnTheQueue(long messageId) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public List<QueueEntry> getMessagesRangeOnTheQueue(long fromPosition, long toPosition) @@ -359,146 +357,137 @@ public class MockAMQQueue implements AMQQueue 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, ServerTransaction storeContext) { - //To change body of implemented methods use File | Settings | File Templates. + } public void removeMessagesFromQueue(long fromMessageId, long toMessageId) { - //To change body of implemented methods use File | Settings | File Templates. + } public long getMaximumMessageSize() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setMaximumMessageSize(long value) { - //To change body of implemented methods use File | Settings | File Templates. + } public long getMaximumMessageCount() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setMaximumMessageCount(long value) { - //To change body of implemented methods use File | Settings | File Templates. + } public long getMaximumQueueDepth() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setMaximumQueueDepth(long value) { - //To change body of implemented methods use File | Settings | File Templates. + } public long getMaximumMessageAge() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setMaximumMessageAge(long maximumMessageAge) { - //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean getBlockOnQueueFull() - { - return false; - } - - public void setBlockOnQueueFull(boolean block) - { + } public long getMinimumAlertRepeatGap() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void deleteMessageFromTop() { - //To change body of implemented methods use File | Settings | File Templates. + } public long clearQueue() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void checkMessageStatus() throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + } public Set<NotificationCheck> getNotificationChecks() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public void flushSubscription(Subscription sub) throws AMQException { - //To change body of implemented methods use File | Settings | File Templates. + } public void deliverAsync(Subscription sub) { - //To change body of implemented methods use File | Settings | File Templates. + } public void deliverAsync() { - //To change body of implemented methods use File | Settings | File Templates. + } public void stop() { - //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. + return false; } public Exchange getAlternateExchange() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } 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. + return null; } - public void checkCapacity(AMQChannel channel) + public void checkCapacity(AMQSessionModel channel) { } public ManagedObject getManagedObject() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public int compareTo(AMQQueue o) { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setMinimumAlertRepeatGap(long value) @@ -508,22 +497,22 @@ public class MockAMQQueue implements AMQQueue public long getCapacity() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setCapacity(long capacity) { - //To change body of implemented methods use File | Settings | File Templates. + } public long getFlowResumeCapacity() { - return 0; //To change body of implemented methods use File | Settings | File Templates. + return 0; } public void setFlowResumeCapacity(long flowResumeCapacity) { - //To change body of implemented methods use File | Settings | File Templates. + } public void configure(ConfigurationPlugin config) @@ -533,7 +522,7 @@ public class MockAMQQueue implements AMQQueue public ConfigurationPlugin getConfiguration() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public AuthorizationHolder getAuthorizationHolder() @@ -612,20 +601,20 @@ public class MockAMQQueue implements AMQQueue } - @Override public int getMaximumDeliveryCount() { return 0; } - @Override public void setMaximumDeliveryCount(int maximumDeliveryCount) { } - @Override public void setAlternateExchange(String exchangeName) { } + public void visit(final Visitor visitor) + { + } } 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 index e2418a85be..b4f8c6d07a 100755 --- 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 @@ -23,7 +23,6 @@ package org.apache.qpid.server.queue; import org.apache.qpid.framing.FieldTable; 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; @@ -107,7 +106,17 @@ public class MockStoredMessage implements StoredMessage<MessageMetaData> return src.limit(); } - public TransactionLog.StoreFuture flushToStore() + + + public ByteBuffer getContent(int offsetInMessage, int size) + { + ByteBuffer buf = ByteBuffer.allocate(size); + getContent(offsetInMessage, buf); + buf.position(0); + return buf; + } + + public MessageStore.StoreFuture flushToStore() { return MessageStore.IMMEDIATE_FUTURE; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java index 7a3f6f701c..cf910208e7 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java @@ -164,7 +164,7 @@ public abstract class QueueEntryListTestBase extends TestCase final QueueEntry head = getTestList().getHead(); assertNull("Head entry should not contain an actual message", head.getMessage()); assertEquals("Unexpected message id for first list entry", getExpectedFirstMsgId(), getTestList().next(head) - .getMessage().getMessageNumber().longValue()); + .getMessage().getMessageNumber()); } /** 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 6c7094cac0..28d52f4fd1 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 @@ -649,9 +649,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase public void onRollback() { } - }); - - + }, 0L); // Check that it is enqueued AMQQueue data = _store.getMessages().get(1L); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java index f3ba6a5495..a873739ca7 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java @@ -162,8 +162,8 @@ public class SimpleQueueEntryListTest extends QueueEntryListTestBase while (entry != null) { assertFalse("Entry " + entry.getMessage().getMessageNumber() + " should not have been deleted", entry.isDeleted()); - assertNotNull("QueueEntry was not found in the list of remaining entries", - remainingMessages.get(entry.getMessage().getMessageNumber().intValue())); + assertNotNull("QueueEntry "+entry.getMessage().getMessageNumber()+" was not found in the list of remaining entries " + remainingMessages, + remainingMessages.get((int)(entry.getMessage().getMessageNumber()))); count++; entry = entry.getNextNode(); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java index eca845644e..34ad0e5668 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java @@ -317,7 +317,7 @@ public class SortedQueueEntryListTest extends QueueEntryListTestBase assertEquals("Sorted queue entry value is not as expected", expectedSortKey, entry.getMessage().getMessageHeader().getHeader("KEY")); assertEquals("Sorted queue entry id is not as expected", - Long.valueOf(expectedMessageId), entry.getMessage().getMessageNumber()); + expectedMessageId, entry.getMessage().getMessageNumber()); } } 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 1d0a9d6316..90adaa1319 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 @@ -558,7 +558,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase /** * Delete the Store Environment path * - * @param configuration The configuration that contains the store environment path. + * @param environmentPath The configuration that contains the store environment path. */ private void cleanup(File environmentPath) { @@ -636,7 +636,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase { //To change body of implemented methods use File | Settings | File Templates. } - }); + }, 0L); } } @@ -710,7 +710,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase if (queue.isDurable() && !queue.isAutoDelete()) { - getVirtualHost().getMessageStore().createQueue(queue, queueArguments); + getVirtualHost().getDurableConfigurationStore().createQueue(queue, queueArguments); } } catch (AMQException e) @@ -754,7 +754,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase getVirtualHost().getExchangeRegistry().registerExchange(exchange); if (durable) { - getVirtualHost().getMessageStore().createExchange(exchange); + getVirtualHost().getDurableConfigurationStore().createExchange(exchange); } } catch (AMQException e) 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 5ff84557d8..44006df517 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 @@ -26,6 +26,7 @@ import org.apache.qpid.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; +import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.message.MessageMetaData; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.exchange.Exchange; @@ -42,18 +43,11 @@ import java.nio.ByteBuffer; */ public class SkeletonMessageStore implements MessageStore { - private final AtomicLong _messageId = new AtomicLong(1); - - public void configure(String base, Configuration 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, @@ -61,7 +55,6 @@ public class SkeletonMessageStore implements MessageStore Configuration config, LogSubject logSubject) throws Exception { - //To change body of implemented methods use File | Settings | File Templates. } public void close() throws Exception @@ -70,31 +63,28 @@ public class SkeletonMessageStore implements MessageStore public <M extends StorableMessageMetaData> StoredMessage<M> addMessage(M metaData) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } - public void removeMessage(Long messageId) - { - } public void createExchange(Exchange exchange) throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } public void removeExchange(Exchange exchange) throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } public void createQueue(AMQQueue queue) throws AMQStoreException @@ -105,63 +95,11 @@ public class SkeletonMessageStore implements MessageStore { } - - - - public List<AMQQueue> createQueues() throws AMQException - { - return null; - } - - public Long getNewMessageId() - { - return _messageId.getAndIncrement(); - } - - public void storeContentBodyChunk( - Long messageId, - int index, - ContentChunk contentBody, - boolean lastContentBody) throws AMQException - { - - } - - public void storeMessageMetaData(Long messageId, MessageMetaData messageMetaData) throws AMQException - { - - } - - public MessageMetaData getMessageMetaData(Long messageId) throws AMQException - { - return null; - } - - public ContentChunk getContentBodyChunk(Long messageId, int index) throws AMQException - { - return null; - } - public boolean isPersistent() { return false; } - 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 ServerMessage getMessage(Long messageNumber) - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - public void removeQueue(final AMQQueue queue) throws AMQStoreException { @@ -172,7 +110,7 @@ public class SkeletonMessageStore implements MessageStore Configuration storeConfiguration, LogSubject logSubject) throws Exception { - //To change body of implemented methods use File | Settings | File Templates. + } public Transaction newTransaction() @@ -180,19 +118,19 @@ public class SkeletonMessageStore implements MessageStore return new Transaction() { - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } public void commitTran() throws AMQStoreException { - //To change body of implemented methods use File | Settings | File Templates. + } public StoreFuture commitTranAsync() throws AMQStoreException @@ -213,7 +151,7 @@ public class SkeletonMessageStore implements MessageStore public void abortTran() throws AMQStoreException { - //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 4dea13d391..fa698f4cf8 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 @@ -82,6 +82,12 @@ public class TestMemoryMessageStore extends MemoryMessageStore return _storedMessage.getContent(offsetInMessage, dst); } + + public ByteBuffer getContent(int offsetInMessage, int size) + { + return _storedMessage.getContent(offsetInMessage, size); + } + public StoreFuture flushToStore() { return _storedMessage.flushToStore(); 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 3593297a05..3804d0dc8e 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 @@ -25,6 +25,8 @@ import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; import org.apache.qpid.AMQStoreException; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.queue.AMQQueue; /** @@ -66,14 +68,14 @@ public class TestableMemoryMessageStore extends MemoryMessageStore private class TestableTransaction implements Transaction { - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { - getMessages().put(messageId, (AMQQueue)queue); + getMessages().put(message.getMessageNumber(), (AMQQueue)queue); } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { - getMessages().remove(messageId); + getMessages().remove(message.getMessageNumber()); } public void commitTran() throws AMQStoreException @@ -143,6 +145,12 @@ public class TestableMemoryMessageStore extends MemoryMessageStore return _storedMessage.getContent(offsetInMessage, dst); } + + public ByteBuffer getContent(int offsetInMessage, int size) + { + return _storedMessage.getContent(offsetInMessage, size); + } + public StoreFuture flushToStore() { return _storedMessage.flushToStore(); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java index 9afed49922..98484db264 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java @@ -29,7 +29,7 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MockAMQQueue; import org.apache.qpid.server.queue.MockQueueEntry; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState; import org.apache.qpid.test.utils.QpidTestCase; @@ -44,7 +44,7 @@ public class AutoCommitTransactionTest extends QpidTestCase { private ServerTransaction _transaction = null; // Class under test - private TransactionLog _transactionLog; + private MessageStore _transactionLog; private AMQQueue _queue; private List<AMQQueue> _queues; private Collection<QueueEntry> _queueEntries; @@ -137,7 +137,7 @@ public class AutoCommitTransactionTest extends QpidTestCase _message = createTestMessage(false); _queues = createTestBaseQueues(new boolean[] {false, false, false}); - _transaction.enqueue(_queues, _message, _action); + _transaction.enqueue(_queues, _message, _action, 0L); assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages()); assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState()); @@ -157,7 +157,7 @@ public class AutoCommitTransactionTest extends QpidTestCase _message = createTestMessage(true); _queues = createTestBaseQueues(new boolean[] {false, false, false}); - _transaction.enqueue(_queues, _message, _action); + _transaction.enqueue(_queues, _message, _action, 0L); assertEquals("Enqueue of persistent message to non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages()); assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState()); @@ -175,7 +175,7 @@ public class AutoCommitTransactionTest extends QpidTestCase _message = createTestMessage(true); _queues = createTestBaseQueues(new boolean[] {false, true, false, true}); - _transaction.enqueue(_queues, _message, _action); + _transaction.enqueue(_queues, _message, _action, 0L); assertEquals("Enqueue of persistent message to durable/non-durable queues must cause messages to be enqueued", 2, _storeTransaction.getNumberOfEnqueuedMessages()); assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState()); @@ -198,7 +198,7 @@ public class AutoCommitTransactionTest extends QpidTestCase try { - _transaction.enqueue(_queues, _message, _action); + _transaction.enqueue(_queues, _message, _action, 0L); fail("Exception not thrown"); } catch (RuntimeException re) diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java index e81fd8e3f1..484beb8fb4 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java @@ -29,7 +29,7 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.MockAMQQueue; import org.apache.qpid.server.queue.MockQueueEntry; import org.apache.qpid.server.queue.QueueEntry; -import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState; import org.apache.qpid.test.utils.QpidTestCase; @@ -51,7 +51,7 @@ public class LocalTransactionTest extends QpidTestCase private MockAction _action1; private MockAction _action2; private MockStoreTransaction _storeTransaction; - private TransactionLog _transactionLog; + private MessageStore _transactionLog; @Override @@ -140,7 +140,7 @@ public class LocalTransactionTest extends QpidTestCase _message = createTestMessage(false); _queues = createTestBaseQueues(new boolean[] {false, false, false}); - _transaction.enqueue(_queues, _message, _action1); + _transaction.enqueue(_queues, _message, _action1, 0L); assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages()); assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState()); @@ -156,7 +156,7 @@ public class LocalTransactionTest extends QpidTestCase _message = createTestMessage(true); _queues = createTestBaseQueues(new boolean[] {false, false, false}); - _transaction.enqueue(_queues, _message, _action1); + _transaction.enqueue(_queues, _message, _action1, 0L); assertEquals("Enqueue of persistent message to non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages()); assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState()); @@ -173,7 +173,7 @@ public class LocalTransactionTest extends QpidTestCase _message = createTestMessage(true); _queues = createTestBaseQueues(new boolean[] {false, true, false, true}); - _transaction.enqueue(_queues, _message, _action1); + _transaction.enqueue(_queues, _message, _action1, 0L); assertEquals("Enqueue of persistent message to durable/non-durable queues must cause messages to be enqueued", 2, _storeTransaction.getNumberOfEnqueuedMessages()); assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState()); @@ -196,7 +196,7 @@ public class LocalTransactionTest extends QpidTestCase try { - _transaction.enqueue(_queues, _message, _action1); + _transaction.enqueue(_queues, _message, _action1, 0L); fail("Exception not thrown"); } catch (RuntimeException re) diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java index 1941feb4ef..063023f5b3 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java @@ -27,11 +27,12 @@ import org.apache.qpid.server.configuration.SessionConfig; import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.StoredMessage; /** * Mock Server Message allowing its persistent flag to be controlled from test. */ -class MockServerMessage implements ServerMessage<MockServerMessage> +class MockServerMessage implements ServerMessage { /** * @@ -83,6 +84,11 @@ class MockServerMessage implements ServerMessage<MockServerMessage> throw new NotImplementedException(); } + public StoredMessage getStoredMessage() + { + throw new NotImplementedException(); + } + public long getExpiration() { throw new NotImplementedException(); @@ -93,12 +99,18 @@ class MockServerMessage implements ServerMessage<MockServerMessage> throw new NotImplementedException(); } + + public ByteBuffer getContent(int offset, int size) + { + throw new NotImplementedException(); + } + public long getArrivalTime() { throw new NotImplementedException(); } - public Long getMessageNumber() + public long getMessageNumber() { return 0L; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java index ff372532ac..bf8fda307a 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java @@ -24,11 +24,11 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.NotImplementedException; import org.apache.qpid.AMQStoreException; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.store.TransactionLog; -import org.apache.qpid.server.store.TransactionLogRecoveryHandler; -import org.apache.qpid.server.store.TransactionLogResource; -import org.apache.qpid.server.store.TransactionLog.StoreFuture; -import org.apache.qpid.server.store.TransactionLog.Transaction; +import org.apache.qpid.server.message.EnqueableMessage; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.store.*; +import org.apache.qpid.server.store.MessageStore.StoreFuture; +import org.apache.qpid.server.store.MessageStore.Transaction; /** * Mock implementation of a (Store) Transaction allow its state to be observed. @@ -61,7 +61,7 @@ class MockStoreTransaction implements Transaction return _state; } - public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { if (_throwExceptionOnQueueOp) { @@ -82,7 +82,7 @@ class MockStoreTransaction implements Transaction return _numberOfEnqueuedMessages; } - public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { if (_throwExceptionOnQueueOp) { @@ -107,10 +107,33 @@ class MockStoreTransaction implements Transaction _state = TransactionState.ABORTED; } - public static TransactionLog createTestTransactionLog(final MockStoreTransaction storeTransaction) + public static MessageStore createTestTransactionLog(final MockStoreTransaction storeTransaction) { - return new TransactionLog() + return new MessageStore() { + public void configureMessageStore(final String name, + final MessageStoreRecoveryHandler recoveryHandler, + final Configuration config, + final LogSubject logSubject) throws Exception + { + //TODO. + } + + public void close() throws Exception + { + //TODO. + } + + public <T extends StorableMessageMetaData> StoredMessage<T> addMessage(final T metaData) + { + return null; //TODO. + } + + public boolean isPersistent() + { + return false; //TODO. + } + public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler, Configuration storeConfiguration, LogSubject logSubject) throws Exception { diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java index c0430665d6..b2cdff89ee 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.Map; import java.util.UUID; import org.apache.qpid.server.binding.BindingFactory; @@ -41,7 +42,6 @@ import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.TransactionLog; import org.apache.qpid.server.protocol.v1_0.LinkRegistry; @@ -66,6 +66,11 @@ public class MockVirtualHost implements VirtualHost } + public BrokerLink createBrokerConnection(final UUID id, final long createTime, final Map<String, String> arguments) + { + return null; + } + public IApplicationRegistry getApplicationRegistry() { return null; @@ -161,10 +166,6 @@ public class MockVirtualHost implements VirtualHost return null; } - public TransactionLog getTransactionLog() - { - return null; - } public void removeBrokerConnection(BrokerLink brokerLink) { diff --git a/qpid/java/broker/src/xsl/qmf.xsl b/qpid/java/broker/src/xsl/qmf.xsl index 3a7e10dac8..1e98c97466 100644 --- a/qpid/java/broker/src/xsl/qmf.xsl +++ b/qpid/java/broker/src/xsl/qmf.xsl @@ -288,6 +288,17 @@ public class <xsl:value-of select="$ClassName"/> extends QMFPackage <xsl:apply-templates select="node()[name()='property' or name()='statistic']" mode="optionalPropertyPresence"/> <xsl:apply-templates select="node()[name()='property' or name()='statistic']" mode="encodeProperty"/> } + + public String toString() + { + return "QMF<xsl:value-of select="@name"/>GetQueryResponseCommand{id=" + getObject().getId() +<xsl:for-each select="node()[name()='property' or name()='statistic']"> +<xsl:if test="@type!='hilo32' and @type!='mmaTime' "> + + ", <xsl:value-of select="@name"/>=" + getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>() +</xsl:if> +</xsl:for-each> + + "}"; + } } @@ -530,6 +541,11 @@ public class <xsl:value-of select="$ClassName"/> extends QMFPackage { return obj.<xsl:value-of select="@name"/>( new <xsl:value-of select="$ClassName"/>ResponseCommandFactory(cmd)<xsl:if test="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">, </xsl:if><xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="prefix">_</xsl:with-param></xsl:apply-templates> ); } + + public String toString() + { + return "<xsl:value-of select="$ClassName"/>["<xsl:for-each select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]"><xsl:if test="preceding-sibling::node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">+ ", "</xsl:if>+ "<xsl:value-of select="@name"/> = " + _<xsl:value-of select="@name"/> </xsl:for-each>+"]"; + } } public final class <xsl:value-of select="$ClassName"/>ResponseCommandFactory diff --git a/qpid/java/build.deps b/qpid/java/build.deps index db28b33b21..c59b9ebaca 100644 --- a/qpid/java/build.deps +++ b/qpid/java/build.deps @@ -146,7 +146,7 @@ management-common.test.libs=${test.libs} ra.libs=${geronimo-j2ee} ${geronimo-jta} ${geronimo-jms} ${slf4j-api} ${geronimo-kernel} ${geronimo-openejb} # optional bdbstore module deps -bdb-je=lib/bdbstore/je-4.0.117.jar +bdb-je=lib/bdbstore/je-5.0.34.jar bdbstore.libs=${bdb-je} bdbstore.test.libs=${test.libs} 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 399534e834..74a0956933 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 @@ -308,7 +308,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate { AMQSession s = (AMQSession) it.next(); // _protocolHandler.addSessionByChannel(s.getChannelId(), s); - reopenChannel(s.getChannelId(), s.getDefaultPrefetchHigh(), s.getDefaultPrefetchLow(), s.getTransacted()); + reopenChannel(s.getChannelId(), s.getDefaultPrefetchHigh(), s.getDefaultPrefetchLow(), s.isTransacted()); s.resubscribe(); } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java index 1df809c67c..92602ac3a2 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java @@ -829,7 +829,7 @@ public abstract class AMQDestination implements Destination, Referenceable dest.setSubject(_subject); dest.setCreate(_create); dest.setAssert(_assert); - dest.setDelete(_create); + dest.setDelete(_delete); dest.setBrowseOnly(_browseOnly); dest.setAddressType(_addressType); dest.setTargetNode(_targetNode); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java index 8984b7ca8c..784b75af10 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java @@ -256,7 +256,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic protected AMQConnection _connection; /** Used to indicate whether or not this is a transactional session. */ - protected boolean _transacted; + protected final boolean _transacted; /** Holds the sessions acknowledgement mode. */ protected final int _acknowledgeMode; @@ -371,7 +371,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic * Set when the dispatcher should direct incoming messages straight into the UnackedMessage list instead of * to the syncRecieveQueue or MessageListener. Used during cleanup, e.g. in Session.recover(). */ - private volatile boolean _usingDispatcherForCleanup; + protected volatile boolean _usingDispatcherForCleanup; /** Used to indicates that the connection to which this session belongs, has been stopped. */ private boolean _connectionStopped; @@ -1583,6 +1583,11 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic return _prefetchLowMark; } + public int getPrefetch() + { + return _prefetchHighMark; + } + public AMQShortString getDefaultQueueExchangeName() { return _connection.getDefaultQueueExchangeName(); @@ -1614,7 +1619,24 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic return _ticket; } - public boolean getTransacted() + /** + * Indicates whether the session is in transacted mode. + * + * @return true if the session is in transacted mode + * @throws IllegalStateException - if session is closed. + */ + public boolean getTransacted() throws JMSException + { + // Sun TCK checks that javax.jms.IllegalStateException is thrown for closed session + // nowhere else this behavior is documented + checkNotClosed(); + return _transacted; + } + + /** + * Indicates whether the session is in transacted mode. + */ + public boolean isTransacted() { return _transacted; } @@ -3047,7 +3069,7 @@ public abstract class AMQSession<C extends BasicMessageConsumer, P extends Basic */ public boolean prefetch() { - return getAMQConnection().getMaxPrefetch() > 0; + return _prefetchHighMark > 0; } /** Signifies that the session has pending sends to commit. */ 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 756b5cacb0..49b77dcc7b 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 @@ -30,7 +30,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Queue; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; @@ -60,23 +59,7 @@ import org.apache.qpid.filter.MessageFilter; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.transport.ExchangeBoundResult; -import org.apache.qpid.transport.ExchangeQueryResult; -import org.apache.qpid.transport.ExecutionErrorCode; -import org.apache.qpid.transport.ExecutionException; -import org.apache.qpid.transport.MessageAcceptMode; -import org.apache.qpid.transport.MessageAcquireMode; -import org.apache.qpid.transport.MessageCreditUnit; -import org.apache.qpid.transport.MessageFlowMode; -import org.apache.qpid.transport.MessageTransfer; -import org.apache.qpid.transport.Option; -import org.apache.qpid.transport.QueueQueryResult; -import org.apache.qpid.transport.Range; -import org.apache.qpid.transport.RangeSet; -import org.apache.qpid.transport.Session; -import org.apache.qpid.transport.SessionException; -import org.apache.qpid.transport.SessionListener; -import org.apache.qpid.transport.TransportException; +import org.apache.qpid.transport.*; import org.apache.qpid.util.Serial; import org.apache.qpid.util.Strings; import org.slf4j.Logger; @@ -141,13 +124,13 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic private long maxAckDelay = Long.getLong("qpid.session.max_ack_delay", 1000); private TimerTask flushTask = null; - private RangeSet unacked = new RangeSet(); + private RangeSet unacked = RangeSetFactory.createRangeSet(); private int unackedCount = 0; /** * Used to store the range of in tx messages */ - private final RangeSet _txRangeSet = new RangeSet(); + private final RangeSet _txRangeSet = RangeSetFactory.createRangeSet(); private int _txSize = 0; //--- constructors @@ -460,7 +443,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic public void sendRecover() throws AMQException, FailoverException { // release all unacked messages - RangeSet all = new RangeSet(); + RangeSet all = RangeSetFactory.createRangeSet(); RangeSet delivered = gatherRangeSet(_unacknowledgedMessageTags); RangeSet prefetched = gatherRangeSet(_prefetchedMessageTags); for (Iterator<Range> deliveredIter = delivered.iterator(); deliveredIter.hasNext();) @@ -483,7 +466,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic private RangeSet gatherRangeSet(ConcurrentLinkedQueue<Long> messageTags) { - RangeSet ranges = new RangeSet(); + RangeSet ranges = RangeSetFactory.createRangeSet(); while (true) { Long tag = messageTags.poll(); @@ -518,7 +501,7 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic public void rejectMessage(long deliveryTag, boolean requeue) { // The value of requeue is always true - RangeSet ranges = new RangeSet(); + RangeSet ranges = RangeSetFactory.createRangeSet(); ranges.add((int) deliveryTag); flushProcessed(ranges, false); if (requeue) @@ -812,11 +795,43 @@ public class AMQSession_0_10 extends AMQSession<BasicMessageConsumer_0_10, Basic { if (suspend) { - for (BasicMessageConsumer consumer : _consumers.values()) - { - getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()), - Option.UNRELIABLE); - } + synchronized (getMessageDeliveryLock()) + { + for (BasicMessageConsumer consumer : _consumers.values()) + { + getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()), + Option.UNRELIABLE); + sync(); + List<Long> tags = consumer.drainReceiverQueueAndRetrieveDeliveryTags(); + _prefetchedMessageTags.addAll(tags); + } + } + + _usingDispatcherForCleanup = true; + syncDispatchQueue(); + _usingDispatcherForCleanup = false; + + RangeSet delivered = gatherRangeSet(_unacknowledgedMessageTags); + RangeSet prefetched = gatherRangeSet(_prefetchedMessageTags); + RangeSet all = RangeSetFactory.createRangeSet(delivered.size() + + prefetched.size()); + + for (Iterator<Range> deliveredIter = delivered.iterator(); deliveredIter.hasNext();) + { + Range range = deliveredIter.next(); + all.add(range); + } + + for (Iterator<Range> prefetchedIter = prefetched.iterator(); prefetchedIter.hasNext();) + { + Range range = prefetchedIter.next(); + all.add(range); + } + + flushProcessed(all, false); + getQpidSession().messageRelease(delivered,Option.SET_REDELIVERED); + getQpidSession().messageRelease(prefetched); + sync(); } else { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java index 96df463481..7daebbff04 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java @@ -21,6 +21,8 @@ package org.apache.qpid.client; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.ArrayList; import java.util.Map; @@ -80,7 +82,7 @@ import org.apache.qpid.transport.TransportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> +public class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> { /** Used for debugging. */ private static final Logger _logger = LoggerFactory.getLogger(AMQSession.class); @@ -96,8 +98,8 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B * @param defaultPrefetchHighMark The maximum number of messages to prefetched before suspending the session. * @param defaultPrefetchLowMark The number of prefetched messages at which to resume the session. */ - AMQSession_0_8(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode, - MessageFactoryRegistry messageFactoryRegistry, int defaultPrefetchHighMark, int defaultPrefetchLowMark) + protected AMQSession_0_8(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode, + MessageFactoryRegistry messageFactoryRegistry, int defaultPrefetchHighMark, int defaultPrefetchLowMark) { super(con,channelId,transacted,acknowledgeMode,messageFactoryRegistry,defaultPrefetchHighMark,defaultPrefetchLowMark); @@ -150,7 +152,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B _logger.debug("Sending ack for delivery tag " + deliveryTag + " on channel " + _channelId); } - getProtocolHandler().writeFrame(ackFrame); + getProtocolHandler().writeFrame(ackFrame, !isTransacted()); _unacknowledgedMessageTags.remove(deliveryTag); } @@ -512,7 +514,7 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B // Bounced message is processed here, away from the mina thread AbstractJMSMessage bouncedMessage = _messageFactoryRegistry.createMessage(0, false, msg.getExchange(), - msg.getRoutingKey(), msg.getContentHeader(), msg.getBodies()); + msg.getRoutingKey(), msg.getContentHeader(), msg.getBodies(),_queueDestinationCache,_topicDestinationCache); AMQConstant errorCode = AMQConstant.getConstant(msg.getReplyCode()); AMQShortString reason = msg.getReplyText(); _logger.debug("Message returned with error code " + errorCode + " (" + reason + ")"); @@ -572,6 +574,16 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B }, _connection).execute(); } + public DestinationCache<AMQQueue> getQueueDestinationCache() + { + return _queueDestinationCache; + } + + public DestinationCache<AMQTopic> getTopicDestinationCache() + { + return _topicDestinationCache; + } + class QueueDeclareOkHandler extends SpecificMethodFrameListener { @@ -613,12 +625,12 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B return okHandler._messageCount; } - protected final boolean tagLE(long tag1, long tag2) + protected boolean tagLE(long tag1, long tag2) { return tag1 <= tag2; } - protected final boolean updateRollbackMark(long currentMark, long deliveryTag) + protected boolean updateRollbackMark(long currentMark, long deliveryTag) { return false; } @@ -695,4 +707,55 @@ public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, B return null; } } + + public abstract static class DestinationCache<T extends AMQDestination> + { + private final Map<AMQShortString, Map<AMQShortString, T>> cache = new HashMap<AMQShortString, Map<AMQShortString, T>>(); + + public T getDestination(AMQShortString exchangeName, AMQShortString routingKey) + { + Map<AMQShortString, T> routingMap = cache.get(exchangeName); + if(routingMap == null) + { + routingMap = new LinkedHashMap<AMQShortString, T>() + { + + protected boolean removeEldestEntry(Map.Entry<AMQShortString, T> eldest) + { + return size() >= 200; + } + }; + cache.put(exchangeName,routingMap); + } + T destination = routingMap.get(routingKey); + if(destination == null) + { + destination = newDestination(exchangeName, routingKey); + routingMap.put(routingKey,destination); + } + return destination; + } + + protected abstract T newDestination(AMQShortString exchangeName, AMQShortString routingKey); + } + + private static class TopicDestinationCache extends DestinationCache<AMQTopic> + { + protected AMQTopic newDestination(AMQShortString exchangeName, AMQShortString routingKey) + { + return new AMQTopic(exchangeName, routingKey, null); + } + } + + private static class QueueDestinationCache extends DestinationCache<AMQQueue> + { + protected AMQQueue newDestination(AMQShortString exchangeName, AMQShortString routingKey) + { + return new AMQQueue(exchangeName, routingKey, routingKey); + } + } + + private final TopicDestinationCache _topicDestinationCache = new TopicDestinationCache(); + private final QueueDestinationCache _queueDestinationCache = new QueueDestinationCache(); + } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java index bb277887aa..3b6179dd07 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java @@ -272,10 +272,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM */ private void acknowledgeMessage(final AbstractJMSMessage message) throws AMQException { - final RangeSet ranges = new RangeSet(); - ranges.add((int) message.getDeliveryTag()); _0_10session.messageAcknowledge - (ranges, + (Range.newInstance((int) message.getDeliveryTag()), _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE); final AMQException amqe = _0_10session.getCurrentException(); @@ -294,9 +292,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM */ private void flushUnwantedMessage(final AbstractJMSMessage message) throws AMQException { - final RangeSet ranges = new RangeSet(); - ranges.add((int) message.getDeliveryTag()); - _0_10session.flushProcessed(ranges,false); + _0_10session.flushProcessed(Range.newInstance((int) message.getDeliveryTag()),false); final AMQException amqe = _0_10session.getCurrentException(); if (amqe != null) @@ -315,10 +311,8 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM private boolean acquireMessage(final AbstractJMSMessage message) throws AMQException { boolean result = false; - final RangeSet ranges = new RangeSet(); - ranges.add((int) message.getDeliveryTag()); - final Acquired acq = _0_10session.getQpidSession().messageAcquire(ranges).get(); + final Acquired acq = _0_10session.getQpidSession().messageAcquire(Range.newInstance((int)message.getDeliveryTag())).get(); final RangeSet acquired = acq.getTransfers(); if (acquired != null && acquired.size() > 0) @@ -451,7 +445,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM { if (_synchronousQueue.size() > 0) { - RangeSet ranges = new RangeSet(); + RangeSet ranges = RangeSetFactory.createRangeSet(); Iterator iterator = _synchronousQueue.iterator(); while (iterator.hasNext()) { @@ -551,7 +545,7 @@ public class BasicMessageConsumer_0_10 extends BasicMessageConsumer<UnprocessedM } else if (getSession().prefetch()) { - capacity = _0_10session.getAMQConnection().getMaxPrefetch(); + capacity = getSession().getPrefetch(); } return capacity; } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java index efcbfd5532..b2f4fcef84 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java @@ -38,11 +38,13 @@ import org.slf4j.LoggerFactory; public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMessage_0_8> { protected final Logger _logger = LoggerFactory.getLogger(getClass()); + private AMQSession_0_8.DestinationCache<AMQTopic> _topicDestinationCache; + private AMQSession_0_8.DestinationCache<AMQQueue> _queueDestinationCache; private final RejectBehaviour _rejectBehaviour; protected BasicMessageConsumer_0_8(int channelId, AMQConnection connection, AMQDestination destination, - String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session, + String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession_0_8 session, AMQProtocolHandler protocolHandler, FieldTable rawSelector, int prefetchHigh, int prefetchLow, boolean exclusive, int acknowledgeMode, boolean browseOnly, boolean autoClose) throws JMSException { @@ -60,6 +62,9 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe consumerArguments.put(AMQPFilterTypes.NO_CONSUME.getValue(), Boolean.TRUE); } + _topicDestinationCache = session.getTopicDestinationCache(); + _queueDestinationCache = session.getQueueDestinationCache(); + if (destination.getRejectBehaviour() != null) { _rejectBehaviour = destination.getRejectBehaviour(); @@ -100,7 +105,8 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe return _messageFactory.createMessage(messageFrame.getDeliveryTag(), messageFrame.isRedelivered(), messageFrame.getExchange(), - messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies()); + messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies(), + _queueDestinationCache, _topicDestinationCache); } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java index 34d2ade723..b2f998cb2c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java @@ -40,6 +40,7 @@ import org.apache.qpid.framing.CompositeAMQDataBlock; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.framing.MethodRegistry; public class BasicMessageProducer_0_8 extends BasicMessageProducer { @@ -53,15 +54,17 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer void declareDestination(AMQDestination destination) { - ExchangeDeclareBody body = getSession().getMethodRegistry().createExchangeDeclareBody(_session.getTicket(), - destination.getExchangeName(), - destination.getExchangeClass(), - false, - false, - false, - false, - true, - null); + final MethodRegistry methodRegistry = getSession().getMethodRegistry(); + ExchangeDeclareBody body = + methodRegistry.createExchangeDeclareBody(_session.getTicket(), + destination.getExchangeName(), + destination.getExchangeClass(), + destination.getExchangeName().toString().startsWith("amq."), + false, + false, + false, + true, + null); // Declare the exchange // Note that the durable and internal arguments are ignored since passive is set to false diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/filter/JMSSelectorFilter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/JMSSelectorFilter.java new file mode 100644 index 0000000000..14cce0aa59 --- /dev/null +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/JMSSelectorFilter.java @@ -0,0 +1,209 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.client.filter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.AMQInternalException; +import org.apache.qpid.client.message.AbstractJMSMessage; +import org.apache.qpid.filter.FilterableMessage; +import org.apache.qpid.filter.SelectorParsingException; +import org.apache.qpid.filter.selector.ParseException; +import org.apache.qpid.filter.selector.SelectorParser; +import org.apache.qpid.filter.BooleanExpression; +import org.apache.qpid.filter.selector.TokenMgrError; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; + + +public class JMSSelectorFilter implements MessageFilter +{ + private static final Logger _logger = LoggerFactory.getLogger(JMSSelectorFilter.class); + + private final String _selector; + private final BooleanExpression _matcher; + + public JMSSelectorFilter(String selector) throws AMQInternalException + { + if (selector == null || "".equals(selector)) + { + throw new IllegalArgumentException("Cannot create a JMSSelectorFilter with a null or empty selector string"); + } + _selector = selector; + if (_logger.isDebugEnabled()) + { + _logger.debug("Created JMSSelectorFilter with selector:" + _selector); + } + try + { + _matcher = new SelectorParser().parse(selector); + } + catch (SelectorParsingException e) + { + throw new AMQInternalException("Unable to parse selector \""+selector+"\"", e); + } + catch (TokenMgrError e) + { + throw new AMQInternalException("Unable to parse selector \""+selector+"\"", e); + } + } + + public boolean matches(AbstractJMSMessage message) + { + try + { + boolean match = _matcher.matches(wrap(message)); + if (_logger.isDebugEnabled()) + { + _logger.debug(message + " match(" + match + ") selector(" + _selector + "): " + _selector); + } + return match; + } + catch (SelectorParsingException e) + { + _logger.warn("Caught exception when evaluating message selector for message " + message, e); + } + return false; + } + + private FilterableMessage wrap(final AbstractJMSMessage message) + { + return new FilterableMessage() + { + public boolean isPersistent() + { + try + { + return message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT; + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public boolean isRedelivered() + { + try + { + return message.getJMSRedelivered(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public Object getHeader(String name) + { + try + { + return message.getObjectProperty(name); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public String getReplyTo() + { + return message.getReplyToString(); + } + + public String getType() + { + try + { + return message.getJMSType(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public byte getPriority() + { + try + { + return (byte) message.getJMSPriority(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public String getMessageId() + { + try + { + return message.getJMSMessageID(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public long getTimestamp() + { + try + { + return message.getJMSTimestamp(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public String getCorrelationId() + { + try + { + return message.getJMSCorrelationID(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + + public long getExpiration() + { + try + { + return message.getJMSExpiration(); + } + catch (JMSException e) + { + throw new SelectorParsingException(e); + } + } + }; + } + + public String getSelector() + { + return _selector; + } +} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/MessageFilter.java index ec0e8ea4c0..fec78d6ba5 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/MessageFilter.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.qpid.filter; +package org.apache.qpid.client.filter; import org.apache.qpid.client.message.AbstractJMSMessage; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java index 6237234c4d..33ca584b34 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java @@ -48,7 +48,10 @@ public class BasicDeliverMethodHandler implements StateAwareMethodListener<Basic body.getExchange(), body.getRoutingKey(), body.getRedelivered()); - _logger.debug("New JmsDeliver method received:" + session); + if(_logger.isDebugEnabled()) + { + _logger.debug("New JmsDeliver method received:" + session); + } session.unprocessedMessageReceived(channelId, msg); } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java index f360b546b2..179ebd66d1 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java @@ -124,7 +124,7 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate */ public static void updateExchangeTypeMapping(Header header, org.apache.qpid.transport.Session session) { - DeliveryProperties deliveryProps = header.get(DeliveryProperties.class); + DeliveryProperties deliveryProps = header.getDeliveryProperties(); if (deliveryProps != null) { String exchange = deliveryProps.getExchange(); @@ -132,7 +132,7 @@ public class AMQMessageDelegate_0_10 extends AbstractAMQMessageDelegate } - MessageProperties msgProps = header.get(MessageProperties.class); + MessageProperties msgProps = header.getMessageProperties(); if (msgProps != null && msgProps.getReplyTo() != null) { String exchange = msgProps.getReplyTo().getExchange(); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java index 9ab03412fe..ab7061c382 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java @@ -31,12 +31,7 @@ import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageNotWriteableException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.CustomJMSXProperty; -import org.apache.qpid.client.JMSAMQException; +import org.apache.qpid.client.*; import org.apache.qpid.collections.ReferenceMap; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -81,7 +76,8 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate // Used when generating a received message object protected AMQMessageDelegate_0_8(long deliveryTag, BasicContentHeaderProperties contentHeader, AMQShortString exchange, - AMQShortString routingKey) + AMQShortString routingKey, AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache, + AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache) { this(contentHeader, deliveryTag); @@ -95,10 +91,10 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate switch (type.intValue()) { case AMQDestination.QUEUE_TYPE: - dest = new AMQQueue(exchange, routingKey, routingKey); + dest = queueDestinationCache.getDestination(exchange, routingKey); break; case AMQDestination.TOPIC_TYPE: - dest = new AMQTopic(exchange, routingKey, null); + dest = topicDestinationCache.getDestination(exchange, routingKey); break; default: // Use the generateDestination method @@ -133,10 +129,66 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate { if (messageId != null) { - getContentHeaderProperties().setMessageId("ID:" + messageId); + getContentHeaderProperties().setMessageId(asShortStringMsgId(messageId)); } } + private static final byte[] HEX_DIGITS = {0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39, + 0x61,0x62,0x63,0x64,0x65,0x66}; + + private static AMQShortString asShortStringMsgId(UUID messageId) + { + long msb = messageId.getMostSignificantBits(); + long lsb = messageId.getLeastSignificantBits(); + + byte[] messageIdBytes = new byte[39]; + messageIdBytes[0] = (byte) 'I'; + messageIdBytes[1] = (byte) 'D'; + messageIdBytes[2] = (byte) ':'; + + messageIdBytes[3] = HEX_DIGITS[(int)((msb >> 60) & 0xFl)]; + messageIdBytes[4] = HEX_DIGITS[(int)((msb >> 56) & 0xFl)]; + messageIdBytes[5] = HEX_DIGITS[(int)((msb >> 52) & 0xFl)]; + messageIdBytes[6] = HEX_DIGITS[(int)((msb >> 48) & 0xFl)]; + messageIdBytes[7] = HEX_DIGITS[(int)((msb >> 44) & 0xFl)]; + messageIdBytes[8] = HEX_DIGITS[(int)((msb >> 40) & 0xFl)]; + messageIdBytes[9] = HEX_DIGITS[(int)((msb >> 36) & 0xFl)]; + messageIdBytes[10] = HEX_DIGITS[(int)((msb >> 32) & 0xFl)]; + + messageIdBytes[11] = (byte) '-'; + messageIdBytes[12] = HEX_DIGITS[(int)((msb >> 28) & 0xFl)]; + messageIdBytes[13] = HEX_DIGITS[(int)((msb >> 24) & 0xFl)]; + messageIdBytes[14] = HEX_DIGITS[(int)((msb >> 20) & 0xFl)]; + messageIdBytes[15] = HEX_DIGITS[(int)((msb >> 16) & 0xFl)]; + messageIdBytes[16] = (byte) '-'; + messageIdBytes[17] = HEX_DIGITS[(int)((msb >> 12) & 0xFl)]; + messageIdBytes[18] = HEX_DIGITS[(int)((msb >> 8) & 0xFl)]; + messageIdBytes[19] = HEX_DIGITS[(int)((msb >> 4) & 0xFl)]; + messageIdBytes[20] = HEX_DIGITS[(int)(msb & 0xFl)]; + messageIdBytes[21] = (byte) '-'; + + messageIdBytes[22] = HEX_DIGITS[(int)((lsb >> 60) & 0xFl)]; + messageIdBytes[23] = HEX_DIGITS[(int)((lsb >> 56) & 0xFl)]; + messageIdBytes[24] = HEX_DIGITS[(int)((lsb >> 52) & 0xFl)]; + messageIdBytes[25] = HEX_DIGITS[(int)((lsb >> 48) & 0xFl)]; + + messageIdBytes[26] = (byte) '-'; + + messageIdBytes[27] = HEX_DIGITS[(int)((lsb >> 44) & 0xFl)]; + messageIdBytes[28] = HEX_DIGITS[(int)((lsb >> 40) & 0xFl)]; + messageIdBytes[29] = HEX_DIGITS[(int)((lsb >> 36) & 0xFl)]; + messageIdBytes[30] = HEX_DIGITS[(int)((lsb >> 32) & 0xFl)]; + messageIdBytes[31] = HEX_DIGITS[(int)((lsb >> 28) & 0xFl)]; + messageIdBytes[32] = HEX_DIGITS[(int)((lsb >> 24) & 0xFl)]; + messageIdBytes[33] = HEX_DIGITS[(int)((lsb >> 20) & 0xFl)]; + messageIdBytes[34] = HEX_DIGITS[(int)((lsb >> 16) & 0xFl)]; + messageIdBytes[35] = HEX_DIGITS[(int)((lsb >> 12) & 0xFl)]; + messageIdBytes[36] = HEX_DIGITS[(int)((lsb >> 8) & 0xFl)]; + messageIdBytes[37] = HEX_DIGITS[(int)((lsb >> 4) & 0xFl)]; + messageIdBytes[38] = HEX_DIGITS[(int)(lsb & 0xFl)]; + + return new AMQShortString(messageIdBytes,0,39); + } public long getJMSTimestamp() throws JMSException { @@ -413,7 +465,7 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate } checkWritableProperties(); - getJmsHeaders().setByte(propertyName, new Byte(b)); + getJmsHeaders().setByte(propertyName, b); } public void setShortProperty(String propertyName, short i) throws JMSException @@ -424,13 +476,13 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate } checkWritableProperties(); - getJmsHeaders().setShort(propertyName, new Short(i)); + getJmsHeaders().setShort(propertyName, i); } public void setIntProperty(String propertyName, int i) throws JMSException { checkWritableProperties(); - getJmsHeaders().setInteger(propertyName, new Integer(i)); + getJmsHeaders().setInteger(propertyName, i); } public void setLongProperty(String propertyName, long l) throws JMSException @@ -441,7 +493,7 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate } checkWritableProperties(); - getJmsHeaders().setLong(propertyName, new Long(l)); + getJmsHeaders().setLong(propertyName, l); } public void setFloatProperty(String propertyName, float f) throws JMSException @@ -452,7 +504,7 @@ public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate } checkWritableProperties(); - getJmsHeaders().setFloat(propertyName, new Float(f)); + getJmsHeaders().setFloat(propertyName, f); } public void setDoubleProperty(String propertyName, double v) throws JMSException diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java index 967a1fb49f..16b71db77e 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java @@ -21,6 +21,9 @@ package org.apache.qpid.client.message; import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession_0_8; +import org.apache.qpid.client.AMQTopic; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; @@ -44,7 +47,9 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory protected AbstractJMSMessage create08MessageWithBody(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange, AMQShortString routingKey, - List bodies) throws AMQException + List bodies, + AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache, + AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache) throws AMQException { ByteBuffer data; final boolean debug = _logger.isDebugEnabled(); @@ -99,7 +104,7 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory AMQMessageDelegate delegate = new AMQMessageDelegate_0_8(messageNbr, (BasicContentHeaderProperties) contentHeader.getProperties(), - exchange, routingKey); + exchange, routingKey, queueDestinationCache, topicDestinationCache); return createMessage(delegate, data); } @@ -149,10 +154,12 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, ContentHeaderBody contentHeader, - AMQShortString exchange, AMQShortString routingKey, List bodies) + AMQShortString exchange, AMQShortString routingKey, List bodies, + AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache, + AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache) throws JMSException, AMQException { - final AbstractJMSMessage msg = create08MessageWithBody(messageNbr, contentHeader, exchange, routingKey, bodies); + final AbstractJMSMessage msg = create08MessageWithBody(messageNbr, contentHeader, exchange, routingKey, bodies, queueDestinationCache, topicDestinationCache); msg.setJMSRedelivered(redelivered); msg.setReceivedFromServer(); return msg; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java index c981c951c3..7f733b9644 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java @@ -29,6 +29,7 @@ import javax.jms.ObjectMessage; import org.apache.qpid.AMQException; import org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream; +import org.apache.qpid.util.ByteBufferInputStream; public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessage { @@ -62,26 +63,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag try { - ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new InputStream() - { - - - @Override - public int read() throws IOException - { - return data.get(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException - { - len = data.remaining() < len ? data.remaining() : len; - data.get(b, off, len); - return len; - } - }); - - _readData = (Serializable) in.readObject(); + _readData = read(data); } catch (IOException e) { @@ -93,7 +75,6 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag } } - public void clearBody() throws JMSException { super.clearBody(); @@ -189,24 +170,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag final ByteBuffer data = _data.duplicate(); try { - ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new InputStream() - { - @Override - public int read() throws IOException - { - return data.get(); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException - { - len = data.remaining() < len ? data.remaining() : len; - data.get(b, off, len); - return len; - } - }); - - return (Serializable) in.readObject(); + return read(data); } catch (ClassNotFoundException e) { @@ -224,4 +188,14 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag } + private Serializable read(final ByteBuffer data) throws IOException, ClassNotFoundException + { + Serializable result = null; + if (data != null && data.hasRemaining()) + { + ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new ByteBufferInputStream(data)); + result = (Serializable) in.readObject(); + } + return result; + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java index f3d96cd855..93c2872b2e 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java @@ -25,6 +25,9 @@ import java.util.List; import javax.jms.JMSException; import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession_0_8; +import org.apache.qpid.client.AMQTopic; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.transport.DeliveryProperties; @@ -36,7 +39,7 @@ public interface MessageFactory AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered, ContentHeaderBody contentHeader, AMQShortString exchange, AMQShortString routingKey, - List bodies) + List bodies, AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache, AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache) throws JMSException, AMQException; AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered, diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java index cdb75fc9a9..15ad3ed89f 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java @@ -28,6 +28,9 @@ import java.nio.ByteBuffer; import javax.jms.JMSException; import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession_0_8; +import org.apache.qpid.client.AMQTopic; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; @@ -93,15 +96,19 @@ public class MessageFactoryRegistry * Create a message. This looks up the MIME type from the content header and instantiates the appropriate * concrete message type. * + * * @param deliveryTag the AMQ message id * @param redelivered true if redelivered * @param contentHeader the content header that was received * @param bodies a list of ContentBody instances @return the message. - * @throws AMQException + * @param queueDestinationCache + *@param topicDestinationCache @throws AMQException * @throws JMSException */ public AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered, AMQShortString exchange, - AMQShortString routingKey, ContentHeaderBody contentHeader, List bodies) + AMQShortString routingKey, ContentHeaderBody contentHeader, List bodies, + AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache, + AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache) throws AMQException, JMSException { BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeader.getProperties(); @@ -118,13 +125,13 @@ public class MessageFactoryRegistry mf = _default; } - return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies); + return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies, queueDestinationCache, topicDestinationCache); } public AbstractJMSMessage createMessage(MessageTransfer transfer) throws AMQException, JMSException { - MessageProperties mprop = transfer.getHeader().get(MessageProperties.class); + MessageProperties mprop = transfer.getHeader().getMessageProperties(); String messageType = ""; if ( mprop == null || mprop.getContentType() == null) { @@ -143,7 +150,7 @@ public class MessageFactoryRegistry boolean redelivered = false; DeliveryProperties deliverProps; - if((deliverProps = transfer.getHeader().get(DeliveryProperties.class)) != null) + if((deliverProps = transfer.getHeader().getDeliveryProperties()) != null) { redelivered = deliverProps.getRedelivered(); } 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 284954edba..8911d4ee3e 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 @@ -20,6 +20,7 @@ */ package org.apache.qpid.client.protocol; +import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -409,10 +410,10 @@ public class AMQProtocolHandler implements ProtocolEngine final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg); // Decode buffer - - for (AMQDataBlock message : dataBlocks) + int size = dataBlocks.size(); + for (int i = 0; i < size; i++) { - + AMQDataBlock message = dataBlocks.get(i); if (PROTOCOL_DEBUG) { _protocolLogger.info(String.format("RECV: [%s] %s", this, message)); @@ -420,10 +421,10 @@ public class AMQProtocolHandler implements ProtocolEngine if(message instanceof AMQFrame) { - final boolean debug = _logger.isDebugEnabled(); + final long msgNumber = ++_messageReceivedCount; - if (debug && ((msgNumber % 1000) == 0)) + if (((msgNumber % 1000) == 0) && _logger.isDebugEnabled()) { _logger.debug("Received " + _messageReceivedCount + " protocol messages"); } @@ -514,12 +515,20 @@ public class AMQProtocolHandler implements ProtocolEngine return getStateManager().createWaiter(states); } - public synchronized void writeFrame(AMQDataBlock frame) + public void writeFrame(AMQDataBlock frame) + { + writeFrame(frame, true); + } + + public synchronized void writeFrame(AMQDataBlock frame, boolean flush) { final ByteBuffer buf = asByteBuffer(frame); _writtenBytes += buf.remaining(); _sender.send(buf); - _sender.flush(); + if(flush) + { + _sender.flush(); + } if (PROTOCOL_DEBUG) { @@ -539,35 +548,51 @@ public class AMQProtocolHandler implements ProtocolEngine } + private static final int REUSABLE_BYTE_BUFFER_CAPACITY = 65 * 1024; + private final byte[] _reusableBytes = new byte[REUSABLE_BYTE_BUFFER_CAPACITY]; + private final ByteBuffer _reusableByteBuffer = ByteBuffer.wrap(_reusableBytes); + private final BytesDataOutput _reusableDataOutput = new BytesDataOutput(_reusableBytes); + private ByteBuffer asByteBuffer(AMQDataBlock block) { - final ByteBuffer buf = ByteBuffer.allocate((int) block.getSize()); + final int size = (int) block.getSize(); - try - { - block.writePayload(new DataOutputStream(new OutputStream() - { + final byte[] data; - @Override - public void write(int b) throws IOException - { - buf.put((byte) b); - } + if(size > REUSABLE_BYTE_BUFFER_CAPACITY) + { + data= new byte[size]; + } + else + { - @Override - public void write(byte[] b, int off, int len) throws IOException - { - buf.put(b, off, len); - } - })); + data = _reusableBytes; + } + _reusableDataOutput.setBuffer(data); + + try + { + block.writePayload(_reusableDataOutput); } catch (IOException e) { throw new RuntimeException(e); } - buf.flip(); + final ByteBuffer buf; + + if(size < REUSABLE_BYTE_BUFFER_CAPACITY) + { + buf = _reusableByteBuffer; + buf.position(0); + } + else + { + buf = ByteBuffer.wrap(data); + } + buf.limit(_reusableDataOutput.length()); + return buf; } @@ -840,4 +865,160 @@ public class AMQProtocolHandler implements ProtocolEngine return _suggestedProtocolVersion; } + private static class BytesDataOutput implements DataOutput + { + int _pos = 0; + byte[] _buf; + + public BytesDataOutput(byte[] buf) + { + _buf = buf; + } + + public void setBuffer(byte[] buf) + { + _buf = buf; + _pos = 0; + } + + public void reset() + { + _pos = 0; + } + + public int length() + { + return _pos; + } + + public void write(int b) + { + _buf[_pos++] = (byte) b; + } + + public void write(byte[] b) + { + System.arraycopy(b, 0, _buf, _pos, b.length); + _pos+=b.length; + } + + + public void write(byte[] b, int off, int len) + { + System.arraycopy(b, off, _buf, _pos, len); + _pos+=len; + + } + + public void writeBoolean(boolean v) + { + _buf[_pos++] = v ? (byte) 1 : (byte) 0; + } + + public void writeByte(int v) + { + _buf[_pos++] = (byte) v; + } + + public void writeShort(int v) + { + _buf[_pos++] = (byte) (v >>> 8); + _buf[_pos++] = (byte) v; + } + + public void writeChar(int v) + { + _buf[_pos++] = (byte) (v >>> 8); + _buf[_pos++] = (byte) v; + } + + public void writeInt(int v) + { + _buf[_pos++] = (byte) (v >>> 24); + _buf[_pos++] = (byte) (v >>> 16); + _buf[_pos++] = (byte) (v >>> 8); + _buf[_pos++] = (byte) v; + } + + public void writeLong(long v) + { + _buf[_pos++] = (byte) (v >>> 56); + _buf[_pos++] = (byte) (v >>> 48); + _buf[_pos++] = (byte) (v >>> 40); + _buf[_pos++] = (byte) (v >>> 32); + _buf[_pos++] = (byte) (v >>> 24); + _buf[_pos++] = (byte) (v >>> 16); + _buf[_pos++] = (byte) (v >>> 8); + _buf[_pos++] = (byte)v; + } + + public void writeFloat(float v) + { + writeInt(Float.floatToIntBits(v)); + } + + public void writeDouble(double v) + { + writeLong(Double.doubleToLongBits(v)); + } + + public void writeBytes(String s) + { + int len = s.length(); + for (int i = 0 ; i < len ; i++) + { + _buf[_pos++] = ((byte)s.charAt(i)); + } + } + + public void writeChars(String s) + { + int len = s.length(); + for (int i = 0 ; i < len ; i++) + { + int v = s.charAt(i); + _buf[_pos++] = (byte) (v >>> 8); + _buf[_pos++] = (byte) v; + } + } + + public void writeUTF(String s) + { + int strlen = s.length(); + + int pos = _pos; + _pos+=2; + + + for (int i = 0; i < strlen; i++) + { + int c = s.charAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) + { + c = s.charAt(i); + _buf[_pos++] = (byte) c; + + } + else if (c > 0x07FF) + { + _buf[_pos++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); + _buf[_pos++] = (byte) (0x80 | ((c >> 6) & 0x3F)); + _buf[_pos++] = (byte) (0x80 | (c & 0x3F)); + } + else + { + _buf[_pos++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); + _buf[_pos++] = (byte) (0x80 | (c & 0x3F)); + } + } + + int len = _pos - (pos + 2); + + _buf[pos++] = (byte) (len >>> 8); + _buf[pos] = (byte) len; + } + + } + + } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/ArithmeticExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/ArithmeticExpression.java deleted file mode 100644 index a86613f10c..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/ArithmeticExpression.java +++ /dev/null @@ -1,268 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; - - -/** - * An expression which performs an operation on two expression values - */ -public abstract class ArithmeticExpression extends BinaryExpression -{ - - protected static final int INTEGER = 1; - protected static final int LONG = 2; - protected static final int DOUBLE = 3; - - - public ArithmeticExpression(Expression left, Expression right) - { - super(left, right); - } - - public static Expression createPlus(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof String) - { - String text = (String) lvalue; - return text + rvalue; - } - else if (lvalue instanceof Number) - { - return plus((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "+"; - } - }; - } - - public static Expression createMinus(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return minus((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "-"; - } - }; - } - - public static Expression createMultiply(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return multiply((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "*"; - } - }; - } - - public static Expression createDivide(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return divide((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "/"; - } - }; - } - - public static Expression createMod(Expression left, Expression right) - { - return new ArithmeticExpression(left, right) - { - - protected Object evaluate(Object lvalue, Object rvalue) - { - if (lvalue instanceof Number) - { - return mod((Number) lvalue, asNumber(rvalue)); - } - - throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue); - } - - public String getExpressionSymbol() - { - return "%"; - } - }; - } - - protected Number plus(Number left, Number right) - { - switch (numberType(left, right)) - { - - case ArithmeticExpression.INTEGER: - return new Integer(left.intValue() + right.intValue()); - - case ArithmeticExpression.LONG: - return new Long(left.longValue() + right.longValue()); - - default: - return new Double(left.doubleValue() + right.doubleValue()); - } - } - - protected Number minus(Number left, Number right) - { - switch (numberType(left, right)) - { - - case ArithmeticExpression.INTEGER: - return new Integer(left.intValue() - right.intValue()); - - case ArithmeticExpression.LONG: - return new Long(left.longValue() - right.longValue()); - - default: - return new Double(left.doubleValue() - right.doubleValue()); - } - } - - protected Number multiply(Number left, Number right) - { - switch (numberType(left, right)) - { - - case ArithmeticExpression.INTEGER: - return new Integer(left.intValue() * right.intValue()); - - case ArithmeticExpression.LONG: - return new Long(left.longValue() * right.longValue()); - - default: - return new Double(left.doubleValue() * right.doubleValue()); - } - } - - protected Number divide(Number left, Number right) - { - return new Double(left.doubleValue() / right.doubleValue()); - } - - protected Number mod(Number left, Number right) - { - return new Double(left.doubleValue() % right.doubleValue()); - } - - private int numberType(Number left, Number right) - { - if (isDouble(left) || isDouble(right)) - { - return ArithmeticExpression.DOUBLE; - } - else if ((left instanceof Long) || (right instanceof Long)) - { - return ArithmeticExpression.LONG; - } - else - { - return ArithmeticExpression.INTEGER; - } - } - - private boolean isDouble(Number n) - { - return (n instanceof Float) || (n instanceof Double); - } - - protected Number asNumber(Object value) - { - if (value instanceof Number) - { - return (Number) value; - } - else - { - throw new RuntimeException("Cannot convert value: " + value + " into a number"); - } - } - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - Object lvalue = left.evaluate(message); - if (lvalue == null) - { - return null; - } - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - return evaluate(lvalue, rvalue); - } - - /** - * @param lvalue - * @param rvalue - * @return - */ - protected abstract Object evaluate(Object lvalue, Object rvalue); - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/BinaryExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/BinaryExpression.java deleted file mode 100644 index f97f858fad..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/BinaryExpression.java +++ /dev/null @@ -1,103 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -/** - * An expression which performs an operation on two expression values. - */ -public abstract class BinaryExpression implements Expression -{ - protected Expression left; - protected Expression right; - - public BinaryExpression(Expression left, Expression right) - { - this.left = left; - this.right = right; - } - - public Expression getLeft() - { - return left; - } - - public Expression getRight() - { - return right; - } - - /** - * @see Object#toString() - */ - public String toString() - { - return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")"; - } - - /** - * TODO: more efficient hashCode() - * - * @see Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see Object#equals(Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Returns the symbol that represents this binary expression. For example, addition is - * represented by "+" - * - * @return - */ - public abstract String getExpressionSymbol(); - - /** - * @param expression - */ - public void setRight(Expression expression) - { - right = expression; - } - - /** - * @param expression - */ - public void setLeft(Expression expression) - { - left = expression; - } - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/ComparisonExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/ComparisonExpression.java deleted file mode 100644 index 55fca853ef..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/ComparisonExpression.java +++ /dev/null @@ -1,589 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import java.util.HashSet; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; - -/** - * A filter performing a comparison of two objects - */ -public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression -{ - - public static BooleanExpression createBetween(Expression value, Expression left, Expression right) - { - return LogicExpression.createAND(ComparisonExpression.createGreaterThanEqual(value, left), ComparisonExpression.createLessThanEqual(value, right)); - } - - public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) - { - return LogicExpression.createOR(ComparisonExpression.createLessThan(value, left), ComparisonExpression.createGreaterThan(value, right)); - } - - private static final HashSet REGEXP_CONTROL_CHARS = new HashSet(); - - static - { - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('.')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('\\')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('[')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character(']')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('^')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('$')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('?')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('*')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('+')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('{')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('}')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('|')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('(')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character(')')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character(':')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('&')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('<')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('>')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('=')); - ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('!')); - } - - static class LikeExpression extends UnaryExpression implements BooleanExpression - { - - Pattern likePattern; - - /** - * @param right - */ - public LikeExpression(Expression right, String like, int escape) - { - super(right); - - StringBuffer regexp = new StringBuffer(like.length() * 2); - regexp.append("\\A"); // The beginning of the input - for (int i = 0; i < like.length(); i++) - { - char c = like.charAt(i); - if (escape == (0xFFFF & c)) - { - i++; - if (i >= like.length()) - { - // nothing left to escape... - break; - } - - char t = like.charAt(i); - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & t)); - } - else if (c == '%') - { - regexp.append(".*?"); // Do a non-greedy match - } - else if (c == '_') - { - regexp.append("."); // match one - } - else if (ComparisonExpression.REGEXP_CONTROL_CHARS.contains(new Character(c))) - { - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & c)); - } - else - { - regexp.append(c); - } - } - - regexp.append("\\z"); // The end of the input - - likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); - } - - /** - * org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() - */ - public String getExpressionSymbol() - { - return "LIKE"; - } - - /** - * org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext) - */ - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - - Object rv = this.getRight().evaluate(message); - - if (rv == null) - { - return null; - } - - if (!(rv instanceof String)) - { - return - Boolean.FALSE; - // throw new RuntimeException("LIKE can only operate on String identifiers. LIKE attemped on: '" + rv.getClass()); - } - - return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE; - } - - public boolean matches(AbstractJMSMessage message) throws AMQInternalException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - public static BooleanExpression createLike(Expression left, String right, String escape) - { - if ((escape != null) && (escape.length() != 1)) - { - throw new RuntimeException( - "The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape); - } - - int c = -1; - if (escape != null) - { - c = 0xFFFF & escape.charAt(0); - } - - return new LikeExpression(left, right, c); - } - - public static BooleanExpression createNotLike(Expression left, String right, String escape) - { - return UnaryExpression.createNOT(ComparisonExpression.createLike(left, right, escape)); - } - - public static BooleanExpression createInFilter(Expression left, List elements) - { - - if (!(left instanceof PropertyExpression)) - { - throw new RuntimeException("Expected a property for In expression, got: " + left); - } - - return UnaryExpression.createInExpression((PropertyExpression) left, elements, false); - - } - - public static BooleanExpression createNotInFilter(Expression left, List elements) - { - - if (!(left instanceof PropertyExpression)) - { - throw new RuntimeException("Expected a property for In expression, got: " + left); - } - - return UnaryExpression.createInExpression((PropertyExpression) left, elements, true); - - } - - public static BooleanExpression createIsNull(Expression left) - { - return ComparisonExpression.doCreateEqual(left, ConstantExpression.NULL); - } - - public static BooleanExpression createIsNotNull(Expression left) - { - return UnaryExpression.createNOT(ComparisonExpression.doCreateEqual(left, ConstantExpression.NULL)); - } - - public static BooleanExpression createNotEqual(Expression left, Expression right) - { - return UnaryExpression.createNOT(ComparisonExpression.createEqual(left, right)); - } - - public static BooleanExpression createEqual(Expression left, Expression right) - { - ComparisonExpression.checkEqualOperand(left); - ComparisonExpression.checkEqualOperand(right); - ComparisonExpression.checkEqualOperandCompatability(left, right); - - return ComparisonExpression.doCreateEqual(left, right); - } - - private static BooleanExpression doCreateEqual(Expression left, Expression right) - { - return new ComparisonExpression(left, right) - { - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - Object lv = left.evaluate(message); - Object rv = right.evaluate(message); - - // Iff one of the values is null - if ((lv == null) ^ (rv == null)) - { - return Boolean.FALSE; - } - - if ((lv == rv) || lv.equals(rv)) - { - return Boolean.TRUE; - } - - if ((lv instanceof Comparable) && (rv instanceof Comparable)) - { - return compare((Comparable) lv, (Comparable) rv); - } - - return Boolean.FALSE; - } - - protected boolean asBoolean(int answer) - { - return answer == 0; - } - - public String getExpressionSymbol() - { - return "="; - } - }; - } - - public static BooleanExpression createGreaterThan(final Expression left, final Expression right) - { - ComparisonExpression.checkLessThanOperand(left); - ComparisonExpression.checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) - { - return answer > 0; - } - - public String getExpressionSymbol() - { - return ">"; - } - }; - } - - public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) - { - ComparisonExpression.checkLessThanOperand(left); - ComparisonExpression.checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - protected boolean asBoolean(int answer) - { - return answer >= 0; - } - - public String getExpressionSymbol() - { - return ">="; - } - }; - } - - public static BooleanExpression createLessThan(final Expression left, final Expression right) - { - ComparisonExpression.checkLessThanOperand(left); - ComparisonExpression.checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) - { - return answer < 0; - } - - public String getExpressionSymbol() - { - return "<"; - } - - }; - } - - public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) - { - ComparisonExpression.checkLessThanOperand(left); - ComparisonExpression.checkLessThanOperand(right); - - return new ComparisonExpression(left, right) - { - - protected boolean asBoolean(int answer) - { - return answer <= 0; - } - - public String getExpressionSymbol() - { - return "<="; - } - }; - } - - /** - * Only Numeric expressions can be used in >, >=, < or <= expressions.s - * - * @param expr - */ - public static void checkLessThanOperand(Expression expr) - { - if (expr instanceof ConstantExpression) - { - Object value = ((ConstantExpression) expr).getValue(); - if (value instanceof Number) - { - return; - } - - // Else it's boolean or a String.. - throw new RuntimeException("Value '" + expr + "' cannot be compared."); - } - - if (expr instanceof BooleanExpression) - { - throw new RuntimeException("Value '" + expr + "' cannot be compared."); - } - } - - /** - * Validates that the expression can be used in == or <> expression. - * Cannot not be NULL TRUE or FALSE litterals. - * - * @param expr - */ - public static void checkEqualOperand(Expression expr) - { - if (expr instanceof ConstantExpression) - { - Object value = ((ConstantExpression) expr).getValue(); - if (value == null) - { - throw new RuntimeException("'" + expr + "' cannot be compared."); - } - } - } - - /** - * - * @param left - * @param right - */ - private static void checkEqualOperandCompatability(Expression left, Expression right) - { - if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression)) - { - if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression)) - { - throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'"); - } - } - } - - /** - * @param left - * @param right - */ - public ComparisonExpression(Expression left, Expression right) - { - super(left, right); - } - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - Comparable lv = (Comparable) left.evaluate(message); - if (lv == null) - { - return null; - } - - Comparable rv = (Comparable) right.evaluate(message); - if (rv == null) - { - return null; - } - - return compare(lv, rv); - } - - protected Boolean compare(Comparable lv, Comparable rv) - { - Class lc = lv.getClass(); - Class rc = rv.getClass(); - // If the the objects are not of the same type, - // try to convert up to allow the comparison. - if (lc != rc) - { - if (lc == Byte.class) - { - if (rc == Short.class) - { - lv = new Short(((Number) lv).shortValue()); - } - else if (rc == Integer.class) - { - lv = new Integer(((Number) lv).intValue()); - } - else if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Short.class) - { - if (rc == Integer.class) - { - lv = new Integer(((Number) lv).intValue()); - } - else if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Integer.class) - { - if (rc == Long.class) - { - lv = new Long(((Number) lv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Long.class) - { - if (rc == Integer.class) - { - rv = new Long(((Number) rv).longValue()); - } - else if (rc == Float.class) - { - lv = new Float(((Number) lv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Float.class) - { - if (rc == Integer.class) - { - rv = new Float(((Number) rv).floatValue()); - } - else if (rc == Long.class) - { - rv = new Float(((Number) rv).floatValue()); - } - else if (rc == Double.class) - { - lv = new Double(((Number) lv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else if (lc == Double.class) - { - if (rc == Integer.class) - { - rv = new Double(((Number) rv).doubleValue()); - } - else if (rc == Long.class) - { - rv = new Double(((Number) rv).doubleValue()); - } - else if (rc == Float.class) - { - rv = new Float(((Number) rv).doubleValue()); - } - else - { - return Boolean.FALSE; - } - } - else - { - return Boolean.FALSE; - } - } - - return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE; - } - - protected abstract boolean asBoolean(int answer); - - public boolean matches(AbstractJMSMessage message) throws AMQInternalException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/ConstantExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/ConstantExpression.java deleted file mode 100644 index 3874d13431..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/ConstantExpression.java +++ /dev/null @@ -1,204 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import java.math.BigDecimal; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; - -/** - * Represents a constant expression - */ -public class ConstantExpression implements Expression -{ - - static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression - { - public BooleanConstantExpression(Object value) - { - super(value); - } - - public boolean matches(AbstractJMSMessage message) throws AMQInternalException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null); - public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE); - public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE); - - private Object value; - - public static ConstantExpression createFromDecimal(String text) - { - - // Strip off the 'l' or 'L' if needed. - if (text.endsWith("l") || text.endsWith("L")) - { - text = text.substring(0, text.length() - 1); - } - - Number value; - try - { - value = new Long(text); - } - catch (NumberFormatException e) - { - // The number may be too big to fit in a long. - value = new BigDecimal(text); - } - - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFromHex(String text) - { - Number value = new Long(Long.parseLong(text.substring(2), 16)); - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFromOctal(String text) - { - Number value = new Long(Long.parseLong(text, 8)); - long l = value.longValue(); - if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE)) - { - value = new Integer(value.intValue()); - } - - return new ConstantExpression(value); - } - - public static ConstantExpression createFloat(String text) - { - Number value = new Double(text); - - return new ConstantExpression(value); - } - - public ConstantExpression(Object value) - { - this.value = value; - } - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - return value; - } - - public Object getValue() - { - return value; - } - - /** - * @see Object#toString() - */ - public String toString() - { - if (value == null) - { - return "NULL"; - } - - if (value instanceof Boolean) - { - return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE"; - } - - if (value instanceof String) - { - return ConstantExpression.encodeString((String) value); - } - - return value.toString(); - } - - /** - * TODO: more efficient hashCode() - * - * @see Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see Object#equals(Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Encodes the value of string so that it looks like it would look like - * when it was provided in a selector. - * - * @param s - * @return - */ - public static String encodeString(String s) - { - StringBuffer b = new StringBuffer(); - b.append('\''); - for (int i = 0; i < s.length(); i++) - { - char c = s.charAt(i); - if (c == '\'') - { - b.append(c); - } - - b.append(c); - } - - b.append('\''); - - return b.toString(); - } - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java deleted file mode 100644 index a1b4aff659..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; -import org.apache.qpid.filter.selector.SelectorParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class JMSSelectorFilter implements MessageFilter -{ - private static final Logger _logger = LoggerFactory.getLogger(JMSSelectorFilter.class); - - private final String _selector; - private final BooleanExpression _matcher; - - public JMSSelectorFilter(String selector) throws AMQInternalException - { - if (selector == null || "".equals(selector)) - { - throw new IllegalArgumentException("Cannot create a JMSSelectorFilter with a null or empty selector string"); - } - _selector = selector; - if (_logger.isDebugEnabled()) - { - _logger.debug("Created JMSSelectorFilter with selector:" + _selector); - } - _matcher = new SelectorParser().parse(selector); - } - - public boolean matches(AbstractJMSMessage message) - { - try - { - boolean match = _matcher.matches(message); - if (_logger.isDebugEnabled()) - { - _logger.debug(message + " match(" + match + ") selector(" + _selector + "): " + _selector); - } - return match; - } - catch (AMQInternalException e) - { - _logger.warn("Caught exception when evaluating message selector for message " + message, e); - } - return false; - } - - public String getSelector() - { - return _selector; - } -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/LogicExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/LogicExpression.java deleted file mode 100644 index 7ef85cbacb..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/LogicExpression.java +++ /dev/null @@ -1,108 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; - - -/** - * A filter performing a comparison of two objects - */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression -{ - - public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) - { - return new LogicExpression(lvalue, rvalue) - { - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - - Boolean lv = (Boolean) left.evaluate(message); - // Can we do an OR shortcut?? - if ((lv != null) && lv.booleanValue()) - { - return Boolean.TRUE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "OR"; - } - }; - } - - public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) - { - return new LogicExpression(lvalue, rvalue) - { - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - - Boolean lv = (Boolean) left.evaluate(message); - - // Can we do an AND shortcut?? - if (lv == null) - { - return null; - } - - if (!lv.booleanValue()) - { - return Boolean.FALSE; - } - - Boolean rv = (Boolean) right.evaluate(message); - - return (rv == null) ? null : rv; - } - - public String getExpressionSymbol() - { - return "AND"; - } - }; - } - - /** - * @param left - * @param right - */ - public LogicExpression(BooleanExpression left, BooleanExpression right) - { - super(left, right); - } - - public abstract Object evaluate(AbstractJMSMessage message) throws AMQInternalException; - - public boolean matches(AbstractJMSMessage message) throws AMQInternalException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java deleted file mode 100644 index 574a1b3888..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java +++ /dev/null @@ -1,300 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import java.util.HashMap; - -import javax.jms.DeliveryMode; -import javax.jms.JMSException; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Represents a property expression - */ -public class PropertyExpression implements Expression -{ - // Constants - defined the same as JMS - private static enum JMSDeliveryMode { NON_PERSISTENT, PERSISTENT } - private static final int DEFAULT_PRIORITY = 4; - - private static final Logger _logger = LoggerFactory.getLogger(PropertyExpression.class); - - private static final HashMap<String, Expression> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression>(); - - static - { - JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - //TODO - return null; - } - }); - JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - return message.getReplyToString(); - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - try - { - return message.getJMSType(); - } - catch (JMSException e) - { - _logger.warn("Error evaluating property", e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - - JMSDeliveryMode mode = JMSDeliveryMode.NON_PERSISTENT; - try - { - mode = message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT ? - JMSDeliveryMode.PERSISTENT : JMSDeliveryMode.NON_PERSISTENT; - - if (_logger.isDebugEnabled()) - { - _logger.debug("JMSDeliveryMode is :" + mode); - } - } - catch (JMSException e) - { - _logger.warn("Error evaluating property",e); - } - - return mode.toString(); - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - try - { - return message.getJMSPriority(); - } - catch (Exception e) - { - _logger.warn("Error evaluating property",e); - } - - return DEFAULT_PRIORITY; - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - - try - { - return message.getJMSMessageID(); - } - catch (JMSException e) - { - _logger.warn("Error evaluating property",e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - try - { - return message.getJMSTimestamp(); - } - catch (Exception e) - { - _logger.warn("Error evaluating property",e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - - try - { - return message.getJMSCorrelationID(); - } - catch (JMSException e) - { - _logger.warn("Error evaluating property",e); - - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - - try - { - return message.getJMSExpiration(); - } - catch (JMSException e) - { - _logger.warn("Error evaluating property",e); - return null; - } - - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - try - { - return message.getJMSRedelivered(); - } - catch (JMSException e) - { - _logger.warn("Error evaluating property",e); - return null; - } - } - }); - - JMS_PROPERTY_EXPRESSIONS.put("JMSMessageID", new Expression() - { - public Object evaluate(AbstractJMSMessage message) - { - try - { - return message.getJMSMessageID(); - } - catch (Exception e) - { - _logger.warn("Error evaluating property",e); - - return null; - } - - } - }); - - } - - private final String name; - private final Expression jmsPropertyExpression; - - public PropertyExpression(String name) - { - this.name = name; - jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name); - } - - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - - if (jmsPropertyExpression != null) - { - return jmsPropertyExpression.evaluate(message); - } - else - { - - try - { - - if (_logger.isDebugEnabled()) - { - _logger.debug("Looking up property:" + name); - _logger.debug("Properties are:" + message.getPropertyNames()); - } - return message.getObjectProperty(name); - } - catch(JMSException e) - { - throw new AMQInternalException("Exception evaluating properties for filter", e); - } - } - } - - public String getName() - { - return name; - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() - { - return name; - } - - /** - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - return name.hashCode(); - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object o) - { - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - return name.equals(((PropertyExpression) o).name); - } - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/UnaryExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/UnaryExpression.java deleted file mode 100644 index 0fc3382b7e..0000000000 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/UnaryExpression.java +++ /dev/null @@ -1,321 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.filter; - -import java.math.BigDecimal; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; - -/** - * An expression which performs an operation on two expression values - */ -public abstract class UnaryExpression implements Expression -{ - - private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); - protected Expression right; - - public static Expression createNegate(Expression left) - { - return new UnaryExpression(left) - { - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue instanceof Number) - { - return UnaryExpression.negate((Number) rvalue); - } - - return null; - } - - public String getExpressionSymbol() - { - return "-"; - } - }; - } - - public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not) - { - - // Use a HashSet if there are many elements. - Collection t; - if (elements.size() == 0) - { - t = null; - } - else if (elements.size() < 5) - { - t = elements; - } - else - { - t = new HashSet(elements); - } - - final Collection inList = t; - - return new BooleanUnaryExpression(right) - { - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (rvalue.getClass() != String.class) - { - return null; - } - - if (((inList != null) && inList.contains(rvalue)) ^ not) - { - return Boolean.TRUE; - } - else - { - return Boolean.FALSE; - } - - } - - public String toString() - { - StringBuffer answer = new StringBuffer(); - answer.append(right); - answer.append(" "); - answer.append(getExpressionSymbol()); - answer.append(" ( "); - - int count = 0; - for (Iterator i = inList.iterator(); i.hasNext();) - { - Object o = (Object) i.next(); - if (count != 0) - { - answer.append(", "); - } - - answer.append(o); - count++; - } - - answer.append(" )"); - - return answer.toString(); - } - - public String getExpressionSymbol() - { - if (not) - { - return "NOT IN"; - } - else - { - return "IN"; - } - } - }; - } - - abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression - { - public BooleanUnaryExpression(Expression left) - { - super(left); - } - - public boolean matches(AbstractJMSMessage message) throws AMQInternalException - { - Object object = evaluate(message); - - return (object != null) && (object == Boolean.TRUE); - } - } - - ; - - public static BooleanExpression createNOT(BooleanExpression left) - { - return new BooleanUnaryExpression(left) - { - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - Boolean lvalue = (Boolean) right.evaluate(message); - if (lvalue == null) - { - return null; - } - - return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; - } - - public String getExpressionSymbol() - { - return "NOT"; - } - }; - } - public static BooleanExpression createBooleanCast(Expression left) - { - return new BooleanUnaryExpression(left) - { - public Object evaluate(AbstractJMSMessage message) throws AMQInternalException - { - Object rvalue = right.evaluate(message); - if (rvalue == null) - { - return null; - } - - if (!rvalue.getClass().equals(Boolean.class)) - { - return Boolean.FALSE; - } - - return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; - } - - public String toString() - { - return right.toString(); - } - - public String getExpressionSymbol() - { - return ""; - } - }; - } - - private static Number negate(Number left) - { - Class clazz = left.getClass(); - if (clazz == Integer.class) - { - return new Integer(-left.intValue()); - } - else if (clazz == Long.class) - { - return new Long(-left.longValue()); - } - else if (clazz == Float.class) - { - return new Float(-left.floatValue()); - } - else if (clazz == Double.class) - { - return new Double(-left.doubleValue()); - } - else if (clazz == BigDecimal.class) - { - // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the - // Selector. Long.MIN_VALUE is too big to store in a Long as a positive so we store it - // as a Big decimal. But it gets Negated right away.. to here we try to covert it back - // to a Long. - BigDecimal bd = (BigDecimal) left; - bd = bd.negate(); - - if (UnaryExpression.BD_LONG_MIN_VALUE.compareTo(bd) == 0) - { - return new Long(Long.MIN_VALUE); - } - - return bd; - } - else - { - throw new RuntimeException("Don't know how to negate: " + left); - } - } - - public UnaryExpression(Expression left) - { - this.right = left; - } - - public Expression getRight() - { - return right; - } - - public void setRight(Expression expression) - { - right = expression; - } - - /** - * @see Object#toString() - */ - public String toString() - { - return "(" + getExpressionSymbol() + " " + right.toString() + ")"; - } - - /** - * TODO: more efficient hashCode() - * - * @see Object#hashCode() - */ - public int hashCode() - { - return toString().hashCode(); - } - - /** - * TODO: more efficient hashCode() - * - * @see Object#equals(Object) - */ - public boolean equals(Object o) - { - - if ((o == null) || !this.getClass().equals(o.getClass())) - { - return false; - } - - return toString().equals(o.toString()); - - } - - /** - * Returns the symbol that represents this binary expression. For example, addition is - * represented by "+" - * - * @return - */ - public abstract String getExpressionSymbol(); - -} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java index 10fd8d2a80..2f1eda6ef2 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java @@ -49,19 +49,9 @@ public class MessagePartListenerAdapter implements MessagePartListener { _currentMsg = new ByteBufferMessage(xfr.getId()); - for (Struct st : xfr.getHeader().getStructs()) - { - if(st instanceof DeliveryProperties) - { - _currentMsg.setDeliveryProperties((DeliveryProperties)st); - - } - else if(st instanceof MessageProperties) - { - _currentMsg.setMessageProperties((MessageProperties)st); - } - - } + Header header = xfr.getHeader(); + _currentMsg.setDeliveryProperties(header.getDeliveryProperties()); + _currentMsg.setMessageProperties(header.getMessageProperties()); ByteBuffer body = xfr.getBody(); diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java index f53fa8d83c..1889577773 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java @@ -588,7 +588,7 @@ public class AMQSession_0_10Test extends TestCase } boolean isTransacted = acknowledgeMode == javax.jms.Session.SESSION_TRANSACTED ? true : false; AMQSession_0_10 session = new AMQSession_0_10(createConnection(throwException), amqConnection, 1, isTransacted, acknowledgeMode, - 1, 1, "test"); + 0, 0, "test"); return session; } @@ -600,7 +600,6 @@ public class AMQSession_0_10Test extends TestCase connection.setSessionFactory(new SessionFactory() { - @Override public Session newSession(Connection conn, Binary name, long expiry) { return new MockSession(conn, new SessionDelegate(), name, expiry, throwException); @@ -611,7 +610,6 @@ public class AMQSession_0_10Test extends TestCase private final class MockMessageListener implements MessageListener { - @Override public void onMessage(Message arg0) { } @@ -710,23 +708,19 @@ public class AMQSession_0_10Test extends TestCase { private List<ProtocolEvent> _sendEvents = new ArrayList<ProtocolEvent>(); - @Override public void setIdleTimeout(int i) { } - @Override public void send(ProtocolEvent msg) { _sendEvents.add(msg); } - @Override public void flush() { } - @Override public void close() { } diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java b/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java index d8d94ba40e..02089cc382 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java @@ -46,8 +46,9 @@ public class BasicMessageConsumer_0_8_Test extends TestCase AMQBindingURL burl = new AMQBindingURL(url); AMQDestination queue = new AMQQueue(burl); - AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn); - BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false); + TestAMQSession testSession = new TestAMQSession(conn); + BasicMessageConsumer_0_8 consumer = + new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false); assertEquals("Reject behaviour was was not as expected", RejectBehaviour.SERVER, consumer.getRejectBehaviour()); } @@ -65,8 +66,9 @@ public class BasicMessageConsumer_0_8_Test extends TestCase final AMQBindingURL burl = new AMQBindingURL(url); final AMQDestination queue = new AMQQueue(burl); - final AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn); - final BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false); + final TestAMQSession testSession = new TestAMQSession(conn); + final BasicMessageConsumer_0_8 consumer = + new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false); assertEquals("Reject behaviour was was not as expected", RejectBehaviour.NORMAL, consumer.getRejectBehaviour()); } @@ -90,8 +92,9 @@ public class BasicMessageConsumer_0_8_Test extends TestCase assertNull("Reject behaviour should have been null", queue.getRejectBehaviour()); - AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn); - BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false); + TestAMQSession testSession = new TestAMQSession(conn); + BasicMessageConsumer_0_8 consumer = + new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false); assertEquals("Reject behaviour was was not as expected", RejectBehaviour.NORMAL, consumer.getRejectBehaviour()); } diff --git a/qpid/java/client/src/test/java/org/apache/qpid/filter/JMSSelectorFilterTest.java b/qpid/java/client/src/test/java/org/apache/qpid/filter/JMSSelectorFilterTest.java deleted file mode 100644 index d4d8ea4350..0000000000 --- a/qpid/java/client/src/test/java/org/apache/qpid/filter/JMSSelectorFilterTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.filter; - -import junit.framework.TestCase; - -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.JMSTextMessage; -import org.apache.qpid.client.message.TestMessageHelper; - -public class JMSSelectorFilterTest extends TestCase -{ - - public void testEmptySelectorFilter() throws Exception - { - try - { - new JMSSelectorFilter(""); - fail("Should not be able to create a JMSSelectorFilter with an empty selector"); - } - catch (IllegalArgumentException iae) - { - // pass - } - } - - public void testNullSelectorFilter() throws Exception - { - try - { - new JMSSelectorFilter(null); - fail("Should not be able to create a JMSSelectorFilter with a null selector"); - } - catch (IllegalArgumentException iae) - { - // pass - } - } - - public void testInvalidSelectorFilter() throws Exception - { - try - { - new JMSSelectorFilter("$%^"); - fail("Unparsable selector so expected AMQInternalException to be thrown"); - } - catch (AMQInternalException amqie) - { - // pass - } - } - - public void testSimpleSelectorFilter() throws Exception - { - MessageFilter simpleSelectorFilter = new JMSSelectorFilter("select=5"); - - assertNotNull("Filter object is null", simpleSelectorFilter); - assertNotNull("Selector string is null", simpleSelectorFilter.getSelector()); - assertEquals("Unexpected selector", "select=5", simpleSelectorFilter.getSelector()); - assertTrue("Filter object is invalid", simpleSelectorFilter != null); - - final JMSTextMessage message = TestMessageHelper.newJMSTextMessage(); - - message.setIntProperty("select", 4); - assertFalse("Selector did match when not expected", simpleSelectorFilter.matches(message)); - message.setIntProperty("select", 5); - assertTrue("Selector didnt match when expected", simpleSelectorFilter.matches(message)); - message.setIntProperty("select", 6); - assertFalse("Selector did match when not expected", simpleSelectorFilter.matches(message)); - } - - public void testFailedMatchingFilter() throws Exception - { - MessageFilter simpleSelectorFilter = new JMSSelectorFilter("select>4"); - - assertNotNull("Filter object is null", simpleSelectorFilter); - assertNotNull("Selector string is null", simpleSelectorFilter.getSelector()); - assertEquals("Unexpected selector", "select>4", simpleSelectorFilter.getSelector()); - assertTrue("Filter object is invalid", simpleSelectorFilter != null); - - final JMSTextMessage message = TestMessageHelper.newJMSTextMessage(); - - message.setStringProperty("select", "5"); - assertFalse("Selector matched when not expected", simpleSelectorFilter.matches(message)); - message.setStringProperty("select", "elephant"); - assertFalse("Selector matched when not expected", simpleSelectorFilter.matches(message)); - message.setBooleanProperty("select", false); - assertFalse("Selector matched when not expected", simpleSelectorFilter.matches(message)); - } -} diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java index 06d0f4a3f9..4c3e9c2390 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java @@ -29,12 +29,7 @@ import javax.jms.Topic; import javax.jms.TopicSubscriber; import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.BasicMessageConsumer_0_8; -import org.apache.qpid.client.BasicMessageProducer_0_8; -import org.apache.qpid.client.MockAMQConnection; +import org.apache.qpid.client.*; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.message.AMQMessageDelegateFactory; import org.apache.qpid.client.protocol.AMQProtocolHandler; @@ -42,7 +37,7 @@ import org.apache.qpid.filter.MessageFilter; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> +public class TestAMQSession extends AMQSession_0_8 { public TestAMQSession(AMQConnection connection) @@ -92,7 +87,7 @@ public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMe return null; } - protected void sendRecover() throws AMQException, FailoverException + public void sendRecover() throws AMQException, FailoverException { } diff --git a/qpid/java/common.xml b/qpid/java/common.xml index 26537e7dfc..4e9e2d1598 100644 --- a/qpid/java/common.xml +++ b/qpid/java/common.xml @@ -61,6 +61,12 @@ <property name="javac.compiler.args" value=""/> <property name="cobertura.dir" value="${project.root}/lib/cobertura" /> + <property name="cobertura.version" value="1.9.4.1" /> + <property name="cobertura.download.url" + value="http://downloads.sourceforge.net/project/cobertura/cobertura/${cobertura.version}/cobertura-${cobertura.version}-bin.zip" /> + <property name="cobertura.zip.filename" value="cobertura-${cobertura.version}-bin.zip" /> + <property name="cobertura.temp.dir" value="${cobertura.dir}"/> + <property name="mllib.dir" value="${project.root}/../python" /> <property name="findbugs.dir" value="${project.root}/lib/findbugs" /> @@ -71,8 +77,8 @@ <path id="cobertura.classpath"> <fileset dir="${cobertura.dir}"> - <include name="cobertura.jar" /> - <include name="lib/**/*.jar" /> + <include name="cobertura-${cobertura.version}/*.jar" /> + <include name="cobertura-${cobertura.version}/**/lib/*.jar" /> </fileset> </path> @@ -192,6 +198,22 @@ <taskdef classpathref="cobertura.classpath" resource="tasks.properties" /> </target> + <!--download Cobertura jar and expand--> + <target name="download-cobertura" description="download Cobertura if not already present" depends="cobertura-check" unless="cobertura.already.exists"> + <mkdir dir="${cobertura.dir}"/> + <echo>Downloading Cobertura ${cobertura.version}</echo> + <get src="${cobertura.download.url}" dest="${cobertura.temp.dir}/${cobertura.zip.filename}" usetimestamp="false" /> + <echo>Extracting Cobertura JAR and dependencies</echo> + <unzip src="${cobertura.temp.dir}/${cobertura.zip.filename}" dest="${cobertura.dir}"/> + <echo>Cleanup Cobertura Download</echo> + <delete file="${cobertura.temp.dir}/${cobertura.zip.filename}"/> + <echo>Done</echo> + </target> + + <target name="cobertura-check"> + <available property="cobertura.already.exists" file="${cobertura.dir}/cobertura-${cobertura.version}" type="dir"/> + </target> + <target name="findbugs-init"> <available file="${findbugs.dir}/findbugs-ant.jar" property="findbugs-ant.jar.present"/> <fail unless="findbugs-ant.jar.present" message="Please follow the instructions at ${findbugs.dir}/README.txt to configure FindBugs"/> diff --git a/qpid/java/common/Composite.tpl b/qpid/java/common/Composite.tpl index 350dd893c8..2cbd6830f6 100644 --- a/qpid/java/common/Composite.tpl +++ b/qpid/java/common/Composite.tpl @@ -245,6 +245,11 @@ if segments: return this; } + public int getBodySize() + { + return this.body == null ? 0 : this.body.remaining(); + } + public final ByteBuffer getBody() { if (this.body == null) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java index 69bf73bb49..1d196534b2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java @@ -24,12 +24,7 @@ import java.io.*; import java.nio.ByteBuffer; import java.util.*; -import org.apache.qpid.framing.AMQDataBlock; -import org.apache.qpid.framing.AMQDataBlockDecoder; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.AMQMethodBodyFactory; -import org.apache.qpid.framing.AMQProtocolVersionException; -import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.*; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; /** @@ -193,24 +188,41 @@ public class AMQDecoder } } + private static class SimpleDataInputStream extends DataInputStream implements MarkableDataInput + { + public SimpleDataInputStream(InputStream in) + { + super(in); + } + + public AMQShortString readAMQShortString() throws IOException + { + return EncodingUtils.readAMQShortString(this); + } + + } + public ArrayList<AMQDataBlock> decodeBuffer(ByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException, IOException { // get prior remaining data from accumulator ArrayList<AMQDataBlock> dataBlocks = new ArrayList<AMQDataBlock>(); - DataInputStream msg; + MarkableDataInput msg; - ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining()); + ByteArrayInputStream bais; + DataInput di; if(!_remainingBufs.isEmpty()) { + bais = new ByteArrayInputStream(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining()); _remainingBufs.add(bais); - msg = new DataInputStream(new RemainingByteArrayInputStream()); + msg = new SimpleDataInputStream(new RemainingByteArrayInputStream()); } else { - msg = new DataInputStream(bais); + bais = null; + msg = new ByteArrayDataInput(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining()); } boolean enoughData = true; @@ -245,11 +257,24 @@ public class AMQDecoder iterator.remove(); } } - if(bais.available()!=0) + + if(bais == null) + { + if(msg.available()!=0) + { + byte[] remaining = new byte[msg.available()]; + msg.read(remaining); + _remainingBufs.add(new ByteArrayInputStream(remaining)); + } + } + else { - byte[] remaining = new byte[bais.available()]; - bais.read(remaining); - _remainingBufs.add(new ByteArrayInputStream(remaining)); + if(bais.available()!=0) + { + byte[] remaining = new byte[bais.available()]; + bais.read(remaining); + _remainingBufs.add(new ByteArrayInputStream(remaining)); + } } } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/codec/MarkableDataInput.java b/qpid/java/common/src/main/java/org/apache/qpid/codec/MarkableDataInput.java new file mode 100644 index 0000000000..2a243a810d --- /dev/null +++ b/qpid/java/common/src/main/java/org/apache/qpid/codec/MarkableDataInput.java @@ -0,0 +1,21 @@ +package org.apache.qpid.codec; + +import org.apache.qpid.framing.AMQShortString; + +import java.io.DataInput; +import java.io.IOException; + +public interface MarkableDataInput extends DataInput +{ + public void mark(int pos); + public void reset() throws IOException; + + int available() throws IOException; + + long skip(long i) throws IOException; + + int read(byte[] b) throws IOException; + + public AMQShortString readAMQShortString() throws IOException; + +} diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java index ebdad12178..363d9f1ccc 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.framing; +import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; @@ -36,7 +37,7 @@ public interface AMQBody */ public abstract int getSize(); - public void writePayload(DataOutputStream buffer) throws IOException; + public void writePayload(DataOutput buffer) throws IOException; void handle(final int channelId, final AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java index 00c1f5aae5..e77e5942e3 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java @@ -21,6 +21,7 @@ package org.apache.qpid.framing; import java.io.DataInputStream; +import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; @@ -42,6 +43,6 @@ public abstract class AMQDataBlock implements EncodableAMQDataBlock * Writes the datablock to the specified buffer. * @param buffer */ - public abstract void writePayload(DataOutputStream buffer) throws IOException; + public abstract void writePayload(DataOutput buffer) throws IOException; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java index 2165cadd14..b6f2fb18ea 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.framing; +import org.apache.qpid.codec.MarkableDataInput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +44,7 @@ public class AMQDataBlockDecoder public AMQDataBlockDecoder() { } - public boolean decodable(DataInputStream in) throws AMQFrameDecodingException, IOException + public boolean decodable(MarkableDataInput in) throws AMQFrameDecodingException, IOException { final int remainingAfterAttributes = in.available() - (1 + 2 + 4 + 1); // type, channel, body length and end byte @@ -65,7 +66,7 @@ public class AMQDataBlockDecoder } - public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, DataInputStream in) + public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, MarkableDataInput in) throws AMQFrameDecodingException, AMQProtocolVersionException, IOException { final byte type = in.readByte(); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java index 6acf60a5b3..9b5699e8ff 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java @@ -20,9 +20,10 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import org.apache.qpid.codec.MarkableDataInput; + +import java.io.*; +import java.io.DataOutput; public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock { @@ -38,7 +39,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock _bodyFrame = bodyFrame; } - public AMQFrame(final DataInputStream in, final int channel, final long bodySize, final BodyFactory bodyFactory) throws AMQFrameDecodingException, IOException + public AMQFrame(final MarkableDataInput in, final int channel, final long bodySize, final BodyFactory bodyFactory) throws AMQFrameDecodingException, IOException { this._channel = channel; this._bodyFrame = bodyFactory.createBody(in,bodySize); @@ -55,7 +56,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { buffer.writeByte(_bodyFrame.getFrameType()); EncodingUtils.writeUnsignedShort(buffer, _channel); @@ -79,7 +80,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock return "Frame channelId: " + _channel + ", bodyFrame: " + String.valueOf(_bodyFrame); } - public static void writeFrame(DataOutputStream buffer, final int channel, AMQBody body) throws IOException + public static void writeFrame(DataOutput buffer, final int channel, AMQBody body) throws IOException { buffer.writeByte(body.getFrameType()); EncodingUtils.writeUnsignedShort(buffer, channel); @@ -89,7 +90,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock } - public static void writeFrames(DataOutputStream buffer, final int channel, AMQBody body1, AMQBody body2) throws IOException + public static void writeFrames(DataOutput buffer, final int channel, AMQBody body1, AMQBody body2) throws IOException { buffer.writeByte(body1.getFrameType()); EncodingUtils.writeUnsignedShort(buffer, channel); @@ -104,7 +105,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock } - public static void writeFrames(DataOutputStream buffer, final int channel, AMQBody body1, AMQBody body2, AMQBody body3) throws IOException + public static void writeFrames(DataOutput buffer, final int channel, AMQBody body1, AMQBody body2, AMQBody body3) throws IOException { buffer.writeByte(body1.getFrameType()); EncodingUtils.writeUnsignedShort(buffer, channel); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java index a076d0e5a1..2170ebf992 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java @@ -25,6 +25,7 @@ import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; +import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; @@ -45,12 +46,12 @@ public interface AMQMethodBody extends AMQBody /** @return unsigned short */ public int getMethod(); - public void writeMethodPayload(DataOutputStream buffer) throws IOException; + public void writeMethodPayload(DataOutput buffer) throws IOException; public int getSize(); - public void writePayload(DataOutputStream buffer) throws IOException; + public void writePayload(DataOutput buffer) throws IOException; //public abstract void populateMethodBodyFromBuffer(ByteBuffer buffer) throws AMQFrameDecodingException; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java index 7fceb082ee..ec6d662726 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java @@ -20,11 +20,13 @@ */ package org.apache.qpid.framing; +import org.apache.qpid.codec.MarkableDataInput; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.DataInput; import java.io.DataInputStream; import java.io.IOException; @@ -39,7 +41,7 @@ public class AMQMethodBodyFactory implements BodyFactory _protocolSession = protocolSession; } - public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException + public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException { return _protocolSession.getMethodRegistry().convertToBody(in, bodySize); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java index c73c1df701..d6f518b123 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java @@ -24,11 +24,12 @@ package org.apache.qpid.framing; import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; +import org.apache.qpid.codec.MarkableDataInput; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; -import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataInput; +import java.io.DataOutput; import java.io.IOException; public abstract class AMQMethodBodyImpl implements AMQMethodBody @@ -101,7 +102,7 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody return 2 + 2 + getBodySize(); } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { EncodingUtils.writeUnsignedShort(buffer, getClazz()); EncodingUtils.writeUnsignedShort(buffer, getMethod()); @@ -109,14 +110,15 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody } - protected byte readByte(DataInputStream buffer) throws IOException + protected byte readByte(DataInput buffer) throws IOException { return buffer.readByte(); } - protected AMQShortString readAMQShortString(DataInputStream buffer) throws IOException + protected AMQShortString readAMQShortString(MarkableDataInput buffer) throws IOException { - return EncodingUtils.readAMQShortString(buffer); + AMQShortString str = buffer.readAMQShortString(); + return str == null ? null : str.intern(false); } protected int getSizeOf(AMQShortString string) @@ -124,27 +126,27 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody return EncodingUtils.encodedShortStringLength(string); } - protected void writeByte(DataOutputStream buffer, byte b) throws IOException + protected void writeByte(DataOutput buffer, byte b) throws IOException { buffer.writeByte(b); } - protected void writeAMQShortString(DataOutputStream buffer, AMQShortString string) throws IOException + protected void writeAMQShortString(DataOutput buffer, AMQShortString string) throws IOException { EncodingUtils.writeShortStringBytes(buffer, string); } - protected int readInt(DataInputStream buffer) throws IOException + protected int readInt(DataInput buffer) throws IOException { return buffer.readInt(); } - protected void writeInt(DataOutputStream buffer, int i) throws IOException + protected void writeInt(DataOutput buffer, int i) throws IOException { buffer.writeInt(i); } - protected FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException + protected FieldTable readFieldTable(DataInput buffer) throws AMQFrameDecodingException, IOException { return EncodingUtils.readFieldTable(buffer); } @@ -154,17 +156,17 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates. } - protected void writeFieldTable(DataOutputStream buffer, FieldTable table) throws IOException + protected void writeFieldTable(DataOutput buffer, FieldTable table) throws IOException { EncodingUtils.writeFieldTableBytes(buffer, table); } - protected long readLong(DataInputStream buffer) throws IOException + protected long readLong(DataInput buffer) throws IOException { return buffer.readLong(); } - protected void writeLong(DataOutputStream buffer, long l) throws IOException + protected void writeLong(DataOutput buffer, long l) throws IOException { buffer.writeLong(l); } @@ -174,27 +176,27 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody return (response == null) ? 4 : response.length + 4; } - protected void writeBytes(DataOutputStream buffer, byte[] data) throws IOException + protected void writeBytes(DataOutput buffer, byte[] data) throws IOException { EncodingUtils.writeBytes(buffer,data); } - protected byte[] readBytes(DataInputStream buffer) throws IOException + protected byte[] readBytes(DataInput buffer) throws IOException { return EncodingUtils.readBytes(buffer); } - protected short readShort(DataInputStream buffer) throws IOException + protected short readShort(DataInput buffer) throws IOException { return EncodingUtils.readShort(buffer); } - protected void writeShort(DataOutputStream buffer, short s) throws IOException + protected void writeShort(DataOutput buffer, short s) throws IOException { EncodingUtils.writeShort(buffer, s); } - protected Content readContent(DataInputStream buffer) + protected Content readContent(DataInput buffer) { return null; } @@ -204,56 +206,56 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody return 0; } - protected void writeContent(DataOutputStream buffer, Content body) + protected void writeContent(DataOutput buffer, Content body) { } - protected byte readBitfield(DataInputStream buffer) throws IOException + protected byte readBitfield(DataInput buffer) throws IOException { return readByte(buffer); } - protected int readUnsignedShort(DataInputStream buffer) throws IOException + protected int readUnsignedShort(DataInput buffer) throws IOException { return buffer.readUnsignedShort(); } - protected void writeBitfield(DataOutputStream buffer, byte bitfield0) throws IOException + protected void writeBitfield(DataOutput buffer, byte bitfield0) throws IOException { buffer.writeByte(bitfield0); } - protected void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException + protected void writeUnsignedShort(DataOutput buffer, int s) throws IOException { EncodingUtils.writeUnsignedShort(buffer, s); } - protected long readUnsignedInteger(DataInputStream buffer) throws IOException + protected long readUnsignedInteger(DataInput buffer) throws IOException { return EncodingUtils.readUnsignedInteger(buffer); } - protected void writeUnsignedInteger(DataOutputStream buffer, long i) throws IOException + protected void writeUnsignedInteger(DataOutput buffer, long i) throws IOException { EncodingUtils.writeUnsignedInteger(buffer, i); } - protected short readUnsignedByte(DataInputStream buffer) throws IOException + protected short readUnsignedByte(DataInput buffer) throws IOException { return (short) buffer.readUnsignedByte(); } - protected void writeUnsignedByte(DataOutputStream buffer, short unsignedByte) throws IOException + protected void writeUnsignedByte(DataOutput buffer, short unsignedByte) throws IOException { EncodingUtils.writeUnsignedByte(buffer, unsignedByte); } - protected long readTimestamp(DataInputStream buffer) throws IOException + protected long readTimestamp(DataInput buffer) throws IOException { return EncodingUtils.readTimestamp(buffer); } - protected void writeTimestamp(DataOutputStream buffer, long t) throws IOException + protected void writeTimestamp(DataOutput buffer, long t) throws IOException { EncodingUtils.writeTimestamp(buffer, t); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java index df4d8bdcb6..88b1ca7189 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java @@ -21,11 +21,12 @@ package org.apache.qpid.framing; -import java.io.DataInputStream; +import org.apache.qpid.codec.MarkableDataInput; + import java.io.IOException; public abstract interface AMQMethodBodyInstanceFactory { - public AMQMethodBody newInstance(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException; + public AMQMethodBody newInstance(MarkableDataInput buffer, long size) throws AMQFrameDecodingException, IOException; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java index cc9a33f4cf..4ff7827d7f 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java @@ -24,8 +24,9 @@ package org.apache.qpid.framing; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.DataInput; import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; import java.util.*; import java.lang.ref.WeakReference; @@ -93,22 +94,44 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt private AMQShortString substring(final int from, final int to) { - return new AMQShortString(_data, from+_offset, to+_offset); + return new AMQShortString(_data, from+_offset, to-from); } - private static final ThreadLocal<Map<AMQShortString, WeakReference<AMQShortString>>> _localInternMap = - new ThreadLocal<Map<AMQShortString, WeakReference<AMQShortString>>>() + private static final int LOCAL_INTERN_CACHE_SIZE = 2048; + + private static final ThreadLocal<Map<AMQShortString, AMQShortString>> _localInternMap = + new ThreadLocal<Map<AMQShortString, AMQShortString>>() { - protected Map<AMQShortString, WeakReference<AMQShortString>> initialValue() + protected Map<AMQShortString, AMQShortString> initialValue() { - return new WeakHashMap<AMQShortString, WeakReference<AMQShortString>>(); + return new LinkedHashMap<AMQShortString, AMQShortString>() + { + + protected boolean removeEldestEntry(Map.Entry<AMQShortString, AMQShortString> eldest) + { + return size() > LOCAL_INTERN_CACHE_SIZE; + } + }; }; }; private static final Map<AMQShortString, WeakReference<AMQShortString>> _globalInternMap = new WeakHashMap<AMQShortString, WeakReference<AMQShortString>>(); + + private static final ThreadLocal<Map<String, WeakReference<AMQShortString>>> _localStringMap = + new ThreadLocal<Map<String, WeakReference<AMQShortString>>>() + { + protected Map<String, WeakReference<AMQShortString>> initialValue() + { + return new WeakHashMap<String, WeakReference<AMQShortString>>(); + }; + }; + + private static final Map<String, WeakReference<AMQShortString>> _globalStringMap = + new WeakHashMap<String, WeakReference<AMQShortString>>(); + private static final Logger _logger = LoggerFactory.getLogger(AMQShortString.class); private final byte[] _data; @@ -200,32 +223,32 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt } - private AMQShortString(DataInputStream data, final int length) throws IOException + private AMQShortString(DataInput data, final int length) throws IOException { if (length > MAX_LENGTH) { throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!"); } byte[] dataBytes = new byte[length]; - data.read(dataBytes); + data.readFully(dataBytes); _data = dataBytes; _offset = 0; _length = length; } - private AMQShortString(final byte[] data, final int from, final int to) + public AMQShortString(byte[] data, final int offset, final int length) { - if (data == null) - { - throw new NullPointerException("Cannot create AMQShortString with null data[]"); - } - int length = to - from; if (length > MAX_LENGTH) { throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!"); } - _offset = from; + if (data == null) + { + throw new NullPointerException("Cannot create AMQShortString with null data[]"); + } + + _offset = offset; _length = length; _data = data; } @@ -234,9 +257,7 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt { if(_data.length != _length) { - byte[] dataBytes = new byte[_length]; - System.arraycopy(_data,_offset,dataBytes,0,_length); - return new AMQShortString(dataBytes,0,_length); + return copy(); } else { @@ -265,7 +286,7 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt return new CharSubSequence(start, end); } - public static AMQShortString readFromBuffer(DataInputStream buffer) throws IOException + public static AMQShortString readFromBuffer(DataInput buffer) throws IOException { final int length = buffer.readUnsignedByte(); if (length == 0) @@ -293,12 +314,12 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt } } - public void writeToBuffer(DataOutputStream buffer) throws IOException + public void writeToBuffer(DataOutput buffer) throws IOException { final int size = length(); //buffer.setAutoExpand(true); - buffer.write((byte) size); + buffer.writeByte(size); buffer.write(_data, _offset, size); } @@ -420,7 +441,17 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt { if (_asString == null) { - _asString = new String(asChars()); + AMQShortString intern = intern(); + + if(intern == this) + { + _asString = new String(asChars()); + } + else + { + _asString = intern.asString(); + } + } return _asString; } @@ -609,42 +640,51 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt public AMQShortString intern() { + return intern(true); + } + + public AMQShortString intern(boolean keep) + { hashCode(); - Map<AMQShortString, WeakReference<AMQShortString>> localMap = + Map<AMQShortString, AMQShortString> localMap = _localInternMap.get(); - WeakReference<AMQShortString> ref = localMap.get(this); - AMQShortString internString; + AMQShortString internString = localMap.get(this); - if(ref != null) + + if(internString != null) { - internString = ref.get(); - if(internString != null) - { - return internString; - } + return internString; } + WeakReference<AMQShortString> ref; synchronized(_globalInternMap) { ref = _globalInternMap.get(this); if((ref == null) || ((internString = ref.get()) == null)) { - internString = shrink(); + internString = keep ? shrink() : copy(); ref = new WeakReference(internString); _globalInternMap.put(internString, ref); } } - localMap.put(internString, ref); + localMap.put(internString, internString); return internString; } + private AMQShortString copy() + { + byte[] dataBytes = new byte[_length]; + System.arraycopy(_data,_offset,dataBytes,0,_length); + return new AMQShortString(dataBytes,0,_length); + } + private int occurences(final byte delim) { int count = 0; @@ -761,7 +801,46 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt public static AMQShortString valueOf(Object obj) { - return obj == null ? null : new AMQShortString(String.valueOf(obj)); + return obj == null ? null : AMQShortString.valueOf(String.valueOf(obj)); + } + + public static AMQShortString valueOf(String obj) + { + if(obj == null) + { + return null; + } + + Map<String, WeakReference<AMQShortString>> localMap = + _localStringMap.get(); + + WeakReference<AMQShortString> ref = localMap.get(obj); + AMQShortString internString; + + if(ref != null) + { + internString = ref.get(); + if(internString != null) + { + return internString; + } + } + + + synchronized(_globalStringMap) + { + + ref = _globalStringMap.get(obj); + if((ref == null) || ((internString = ref.get()) == null)) + { + internString = (new AMQShortString(obj)).intern(); + ref = new WeakReference<AMQShortString>(internString); + _globalStringMap.put(obj, ref); + } + + } + localMap.put(obj, ref); + return internString; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java index f3da64e639..5c89af09c4 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataInput; +import java.io.DataOutput; import java.io.IOException; import java.math.BigDecimal; @@ -61,12 +61,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeLongStringBytes(buffer, (String) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readLongString(buffer); } @@ -107,12 +107,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeUnsignedInteger(buffer, (Long) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readUnsignedInteger(buffer); } @@ -138,7 +138,7 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { BigDecimal bd = (BigDecimal) value; @@ -151,7 +151,7 @@ public enum AMQType EncodingUtils.writeInteger(buffer, unscaled); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { byte places = EncodingUtils.readByte(buffer); @@ -183,12 +183,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeLong(buffer, (Long) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readLong(buffer); } @@ -247,7 +247,7 @@ public enum AMQType * @param value An instance of the type. * @param buffer The byte buffer to write it to. */ - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { // Ensure that the value is a FieldTable. if (!(value instanceof FieldTable)) @@ -268,7 +268,7 @@ public enum AMQType * * @return An instance of the type. */ - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { try { @@ -302,10 +302,10 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) + public void writeValueImpl(Object value, DataOutput buffer) { } - public Object readValueFromBuffer(DataInputStream buffer) + public Object readValueFromBuffer(DataInput buffer) { return null; } @@ -331,12 +331,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeLongstr(buffer, (byte[]) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readLongstr(buffer); } @@ -361,12 +361,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeLongStringBytes(buffer, (String) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readLongString(buffer); } @@ -392,12 +392,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeLongStringBytes(buffer, (String) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readLongString(buffer); } @@ -427,12 +427,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeBoolean(buffer, (Boolean) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readBoolean(buffer); } @@ -462,12 +462,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeChar(buffer, (Character) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readChar(buffer); } @@ -497,12 +497,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeByte(buffer, (Byte) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readByte(buffer); } @@ -536,12 +536,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeShort(buffer, (Short) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readShort(buffer); } @@ -578,12 +578,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeInteger(buffer, (Integer) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readInteger(buffer); } @@ -596,6 +596,22 @@ public enum AMQType return EncodingUtils.encodedLongLength(); } + public int getEncodingSize(long value) + { + return EncodingUtils.encodedLongLength(); + } + + public AMQTypedValue asTypedValue(long value) + { + return AMQTypedValue.createAMQTypedValue(value); + } + + public void writeToBuffer(long value, DataOutput buffer) throws IOException + { + buffer.writeByte(identifier()); + EncodingUtils.writeLong(buffer, value); + } + public Object toNativeValue(Object value) { if (value instanceof Long) @@ -625,12 +641,18 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeLong(buffer, (Long) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public long readLongFromBuffer(DataInput buffer) throws IOException + { + return EncodingUtils.readLong(buffer); + } + + + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readLong(buffer); } @@ -660,12 +682,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeFloat(buffer, (Float) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readFloat(buffer); } @@ -699,12 +721,12 @@ public enum AMQType } } - public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException + public void writeValueImpl(Object value, DataOutput buffer) throws IOException { EncodingUtils.writeDouble(buffer, (Double) value); } - public Object readValueFromBuffer(DataInputStream buffer) throws IOException + public Object readValueFromBuffer(DataInput buffer) throws IOException { return EncodingUtils.readDouble(buffer); } @@ -761,7 +783,7 @@ public enum AMQType */ public AMQTypedValue asTypedValue(Object value) { - return new AMQTypedValue(this, toNativeValue(value)); + return AMQTypedValue.createAMQTypedValue(this, toNativeValue(value)); } /** @@ -771,7 +793,7 @@ public enum AMQType * @param value An instance of the type. * @param buffer The byte buffer to write it to. */ - public void writeToBuffer(Object value, DataOutputStream buffer) throws IOException + public void writeToBuffer(Object value, DataOutput buffer) throws IOException { buffer.writeByte(identifier()); writeValueImpl(value, buffer); @@ -783,7 +805,7 @@ public enum AMQType * @param value An instance of the type. * @param buffer The byte buffer to write it to. */ - abstract void writeValueImpl(Object value, DataOutputStream buffer) throws IOException; + abstract void writeValueImpl(Object value, DataOutput buffer) throws IOException; /** * Reads an instance of the type from a specified byte buffer. @@ -792,5 +814,5 @@ public enum AMQType * * @return An instance of the type. */ - abstract Object readValueFromBuffer(DataInputStream buffer) throws IOException; + abstract Object readValueFromBuffer(DataInput buffer) throws IOException; } 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 1dbedca362..f64164c10b 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 @@ -20,9 +20,7 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import java.io.*; import java.util.Date; import java.util.Map; import java.math.BigDecimal; @@ -42,81 +40,223 @@ import java.math.BigDecimal; * <tr><td> Extract the value from a fully typed AMQP value. * </table> */ -public class AMQTypedValue +public abstract class AMQTypedValue { - /** The type of the value. */ - private final AMQType _type; - /** The Java native representation of the AMQP typed value. */ - private final Object _value; + public abstract AMQType getType(); - public AMQTypedValue(AMQType type, Object value) + public abstract Object getValue(); + + public abstract void writeToBuffer(DataOutput buffer) throws IOException; + + public abstract int getEncodingSize(); + + + private static final class GenericTypedValue extends AMQTypedValue { - if (type == null) + /** The type of the value. */ + private final AMQType _type; + + /** The Java native representation of the AMQP typed value. */ + private final Object _value; + + private GenericTypedValue(AMQType type, Object value) { - throw new NullPointerException("Cannot create a typed value with null type"); + if (type == null) + { + throw new NullPointerException("Cannot create a typed value with null type"); + } + + _type = type; + _value = type.toNativeValue(value); } - _type = type; - _value = type.toNativeValue(value); - } + private GenericTypedValue(AMQType type, DataInput buffer) throws IOException + { + _type = type; + _value = type.readValueFromBuffer(buffer); + } + + + public AMQType getType() + { + return _type; + } + + public Object getValue() + { + return _value; + } + + public void writeToBuffer(DataOutput buffer) throws IOException + { + _type.writeToBuffer(_value, buffer); + } + + public int getEncodingSize() + { + return _type.getEncodingSize(_value); + } + + + public String toString() + { + return "[" + getType() + ": " + getValue() + "]"; + } + + + public boolean equals(Object o) + { + if(o instanceof GenericTypedValue) + { + GenericTypedValue other = (GenericTypedValue) o; + return _type == other._type && (_value == null ? other._value == null : _value.equals(other._value)); + } + else + { + return false; + } + } + + public int hashCode() + { + return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode()); + } - private AMQTypedValue(AMQType type, DataInputStream buffer) throws IOException - { - _type = type; - _value = type.readValueFromBuffer(buffer); } - public AMQType getType() + private static final class LongTypedValue extends AMQTypedValue { - return _type; + + private final long _value; + + private LongTypedValue(long value) + { + _value = value; + } + + public LongTypedValue(DataInput buffer) throws IOException + { + _value = EncodingUtils.readLong(buffer); + } + + public AMQType getType() + { + return AMQType.LONG; + } + + + public Object getValue() + { + return _value; + } + + public void writeToBuffer(DataOutput buffer) throws IOException + { + EncodingUtils.writeByte(buffer,AMQType.LONG.identifier()); + EncodingUtils.writeLong(buffer,_value); + } + + + public int getEncodingSize() + { + return EncodingUtils.encodedLongLength(); + } } - public Object getValue() + private static final class IntTypedValue extends AMQTypedValue { - return _value; + @Override + public String toString() + { + return "[INT: " + String.valueOf(_value) + "]"; + } + + private final int _value; + + public IntTypedValue(int value) + { + _value = value; + } + + public AMQType getType() + { + return AMQType.INT; + } + + + public Object getValue() + { + return _value; + } + + public void writeToBuffer(DataOutput buffer) throws IOException + { + EncodingUtils.writeByte(buffer,AMQType.INT.identifier()); + EncodingUtils.writeInteger(buffer, _value); + } + + + public int getEncodingSize() + { + return EncodingUtils.encodedIntegerLength(); + } } - public void writeToBuffer(DataOutputStream buffer) throws IOException + + public static AMQTypedValue readFromBuffer(DataInput buffer) throws IOException { - _type.writeToBuffer(_value, buffer); + AMQType type = AMQTypeMap.getType(buffer.readByte()); + + switch(type) + { + case LONG: + return new LongTypedValue(buffer); + + case INT: + int value = EncodingUtils.readInteger(buffer); + return createAMQTypedValue(value); + + default: + return new GenericTypedValue(type, buffer); + } + } - public int getEncodingSize() + private static final AMQTypedValue[] INT_VALUES = new AMQTypedValue[16]; + static { - return _type.getEncodingSize(_value); + for(int i = 0 ; i < 16; i ++) + { + INT_VALUES[i] = new IntTypedValue(i); + } } - public static AMQTypedValue readFromBuffer(DataInputStream buffer) throws IOException + public static AMQTypedValue createAMQTypedValue(int i) { - AMQType type = AMQTypeMap.getType(buffer.readByte()); - - return new AMQTypedValue(type, buffer); + return (i & 0x0f) == i ? INT_VALUES[i] : new IntTypedValue(i); } - public String toString() + + public static AMQTypedValue createAMQTypedValue(long value) { - return "[" + getType() + ": " + getValue() + "]"; + return new LongTypedValue(value); } - - public boolean equals(Object o) + public static AMQTypedValue createAMQTypedValue(AMQType type, Object value) { - if(o instanceof AMQTypedValue) + switch(type) { - AMQTypedValue other = (AMQTypedValue) o; - return _type == other._type && (_value == null ? other._value == null : _value.equals(other._value)); - } - else - { - return false; + case LONG: + return new LongTypedValue((Long) AMQType.LONG.toNativeValue(value)); + case INT: + return new IntTypedValue((Integer) AMQType.INT.toNativeValue(value)); + + default: + return new GenericTypedValue(type, value); } } - public int hashCode() - { - return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode()); - } public static AMQTypedValue toTypedValue(Object val) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java index 57622b5054..2739f7d14b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java @@ -20,8 +20,9 @@ */ package org.apache.qpid.framing; +import java.io.DataInput; import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; import org.slf4j.Logger; @@ -80,6 +81,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti private static final int USER_ID_MASK = 1 << 4; private static final int APPLICATION_ID_MASK = 1 << 3; private static final int CLUSTER_ID_MASK = 1 << 2; + private byte[] _encodedForm; public BasicContentHeaderProperties() @@ -87,6 +89,12 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public int getPropertyListSize() { + if(_encodedForm != null && (_headers == null || _headers.isClean())) + { + return _encodedForm.length; + } + else + { int size = 0; if ((_propertyFlags & (CONTENT_TYPE_MASK)) > 0) @@ -167,6 +175,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti } return size; + } } public void setPropertyFlags(int propertyFlags) @@ -179,87 +188,94 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti return _propertyFlags; } - public void writePropertyListPayload(DataOutputStream buffer) throws IOException + public void writePropertyListPayload(DataOutput buffer) throws IOException { - if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0) + if(_encodedForm != null && (_headers == null || !_headers.isClean())) { - EncodingUtils.writeShortStringBytes(buffer, _contentType); + buffer.write(_encodedForm); } - - if ((_propertyFlags & ENCODING_MASK) != 0) + else { - EncodingUtils.writeShortStringBytes(buffer, _encoding); - } + if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _contentType); + } - if ((_propertyFlags & HEADERS_MASK) != 0) - { - EncodingUtils.writeFieldTableBytes(buffer, _headers); - } + if ((_propertyFlags & ENCODING_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _encoding); + } - if ((_propertyFlags & DELIVERY_MODE_MASK) != 0) - { - buffer.writeByte(_deliveryMode); - } + if ((_propertyFlags & HEADERS_MASK) != 0) + { + EncodingUtils.writeFieldTableBytes(buffer, _headers); + } - if ((_propertyFlags & PRIORITY_MASK) != 0) - { - buffer.writeByte(_priority); - } + if ((_propertyFlags & DELIVERY_MODE_MASK) != 0) + { + buffer.writeByte(_deliveryMode); + } - if ((_propertyFlags & CORRELATION_ID_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _correlationId); - } + if ((_propertyFlags & PRIORITY_MASK) != 0) + { + buffer.writeByte(_priority); + } - if ((_propertyFlags & REPLY_TO_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _replyTo); - } + if ((_propertyFlags & CORRELATION_ID_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _correlationId); + } - if ((_propertyFlags & EXPIRATION_MASK) != 0) - { - if (_expiration == 0L) + if ((_propertyFlags & REPLY_TO_MASK) != 0) { - EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING); + EncodingUtils.writeShortStringBytes(buffer, _replyTo); } - else + + if ((_propertyFlags & EXPIRATION_MASK) != 0) { - EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration)); + if (_expiration == 0L) + { + EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING); + } + else + { + EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration)); + } } - } - if ((_propertyFlags & MESSAGE_ID_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _messageId); - } + if ((_propertyFlags & MESSAGE_ID_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _messageId); + } - if ((_propertyFlags & TIMESTAMP_MASK) != 0) - { - EncodingUtils.writeTimestamp(buffer, _timestamp); - } + if ((_propertyFlags & TIMESTAMP_MASK) != 0) + { + EncodingUtils.writeTimestamp(buffer, _timestamp); + } - if ((_propertyFlags & TYPE_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _type); - } + if ((_propertyFlags & TYPE_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _type); + } - if ((_propertyFlags & USER_ID_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _userId); - } + if ((_propertyFlags & USER_ID_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _userId); + } - if ((_propertyFlags & APPLICATION_ID_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _appId); - } + if ((_propertyFlags & APPLICATION_ID_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _appId); + } - if ((_propertyFlags & CLUSTER_ID_MASK) != 0) - { - EncodingUtils.writeShortStringBytes(buffer, _clusterId); + if ((_propertyFlags & CLUSTER_ID_MASK) != 0) + { + EncodingUtils.writeShortStringBytes(buffer, _clusterId); + } } } - public void populatePropertiesFromBuffer(DataInputStream buffer, int propertyFlags, int size) throws AMQFrameDecodingException, IOException + public void populatePropertiesFromBuffer(DataInput buffer, int propertyFlags, int size) throws AMQFrameDecodingException, IOException { _propertyFlags = propertyFlags; @@ -268,26 +284,40 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti _logger.debug("Property flags: " + _propertyFlags); } - decode(buffer); + _encodedForm = new byte[size]; + buffer.readFully(_encodedForm); + + ByteArrayDataInput input = new ByteArrayDataInput(_encodedForm); + + decode(input); + } - private void decode(DataInputStream buffer) throws IOException, AMQFrameDecodingException + private void decode(ByteArrayDataInput buffer) throws IOException, AMQFrameDecodingException { // ByteBuffer buffer = ByteBuffer.wrap(_encodedForm); + int headersOffset = 0; + if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0) { - _contentType = EncodingUtils.readAMQShortString(buffer); + _contentType = buffer.readAMQShortString(); + headersOffset += EncodingUtils.encodedShortStringLength(_contentType); } if ((_propertyFlags & ENCODING_MASK) != 0) { - _encoding = EncodingUtils.readAMQShortString(buffer); + _encoding = buffer.readAMQShortString(); + headersOffset += EncodingUtils.encodedShortStringLength(_encoding); } if ((_propertyFlags & HEADERS_MASK) != 0) { - _headers = EncodingUtils.readFieldTable(buffer); + long length = EncodingUtils.readUnsignedInteger(buffer); + + _headers = new FieldTable(_encodedForm, headersOffset+4, (int)length); + + buffer.skipBytes((int)length); } if ((_propertyFlags & DELIVERY_MODE_MASK) != 0) @@ -302,12 +332,12 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti if ((_propertyFlags & CORRELATION_ID_MASK) != 0) { - _correlationId = EncodingUtils.readAMQShortString(buffer); + _correlationId = buffer.readAMQShortString(); } if ((_propertyFlags & REPLY_TO_MASK) != 0) { - _replyTo = EncodingUtils.readAMQShortString(buffer); + _replyTo = buffer.readAMQShortString(); } if ((_propertyFlags & EXPIRATION_MASK) != 0) @@ -317,7 +347,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti if ((_propertyFlags & MESSAGE_ID_MASK) != 0) { - _messageId = EncodingUtils.readAMQShortString(buffer); + _messageId = buffer.readAMQShortString(); } if ((_propertyFlags & TIMESTAMP_MASK) != 0) @@ -327,22 +357,22 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti if ((_propertyFlags & TYPE_MASK) != 0) { - _type = EncodingUtils.readAMQShortString(buffer); + _type = buffer.readAMQShortString(); } if ((_propertyFlags & USER_ID_MASK) != 0) { - _userId = EncodingUtils.readAMQShortString(buffer); + _userId = buffer.readAMQShortString(); } if ((_propertyFlags & APPLICATION_ID_MASK) != 0) { - _appId = EncodingUtils.readAMQShortString(buffer); + _appId = buffer.readAMQShortString(); } if ((_propertyFlags & CLUSTER_ID_MASK) != 0) { - _clusterId = EncodingUtils.readAMQShortString(buffer); + _clusterId = buffer.readAMQShortString(); } @@ -363,11 +393,12 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= (CONTENT_TYPE_MASK); _contentType = contentType; + _encodedForm = null; } public void setContentType(String contentType) { - setContentType((contentType == null) ? null : new AMQShortString(contentType)); + setContentType((contentType == null) ? null : AMQShortString.valueOf(contentType)); } public String getEncodingAsString() @@ -384,13 +415,15 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setEncoding(String encoding) { _propertyFlags |= ENCODING_MASK; - _encoding = (encoding == null) ? null : new AMQShortString(encoding); + _encoding = (encoding == null) ? null : AMQShortString.valueOf(encoding); + _encodedForm = null; } public void setEncoding(AMQShortString encoding) { _propertyFlags |= ENCODING_MASK; _encoding = encoding; + _encodedForm = null; } public FieldTable getHeaders() @@ -407,6 +440,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= HEADERS_MASK; _headers = headers; + _encodedForm = null; } public byte getDeliveryMode() @@ -418,6 +452,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= DELIVERY_MODE_MASK; _deliveryMode = deliveryMode; + _encodedForm = null; } public byte getPriority() @@ -429,6 +464,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= PRIORITY_MASK; _priority = priority; + _encodedForm = null; } public AMQShortString getCorrelationId() @@ -443,13 +479,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setCorrelationId(String correlationId) { - setCorrelationId((correlationId == null) ? null : new AMQShortString(correlationId)); + setCorrelationId((correlationId == null) ? null : AMQShortString.valueOf(correlationId)); } public void setCorrelationId(AMQShortString correlationId) { _propertyFlags |= CORRELATION_ID_MASK; _correlationId = correlationId; + _encodedForm = null; } public String getReplyToAsString() @@ -464,13 +501,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setReplyTo(String replyTo) { - setReplyTo((replyTo == null) ? null : new AMQShortString(replyTo)); + setReplyTo((replyTo == null) ? null : AMQShortString.valueOf(replyTo)); } public void setReplyTo(AMQShortString replyTo) { _propertyFlags |= REPLY_TO_MASK; _replyTo = replyTo; + _encodedForm = null; } public long getExpiration() @@ -482,6 +520,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= EXPIRATION_MASK; _expiration = expiration; + _encodedForm = null; } public AMQShortString getMessageId() @@ -498,12 +537,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= MESSAGE_ID_MASK; _messageId = (messageId == null) ? null : new AMQShortString(messageId); + _encodedForm = null; } public void setMessageId(AMQShortString messageId) { _propertyFlags |= MESSAGE_ID_MASK; _messageId = messageId; + _encodedForm = null; } public long getTimestamp() @@ -515,6 +556,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti { _propertyFlags |= TIMESTAMP_MASK; _timestamp = timestamp; + _encodedForm = null; } public String getTypeAsString() @@ -529,13 +571,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setType(String type) { - setType((type == null) ? null : new AMQShortString(type)); + setType((type == null) ? null : AMQShortString.valueOf(type)); } public void setType(AMQShortString type) { _propertyFlags |= TYPE_MASK; _type = type; + _encodedForm = null; } public String getUserIdAsString() @@ -550,13 +593,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setUserId(String userId) { - setUserId((userId == null) ? null : new AMQShortString(userId)); + setUserId((userId == null) ? null : AMQShortString.valueOf(userId)); } public void setUserId(AMQShortString userId) { _propertyFlags |= USER_ID_MASK; _userId = userId; + _encodedForm = null; } public String getAppIdAsString() @@ -571,13 +615,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setAppId(String appId) { - setAppId((appId == null) ? null : new AMQShortString(appId)); + setAppId((appId == null) ? null : AMQShortString.valueOf(appId)); } public void setAppId(AMQShortString appId) { _propertyFlags |= APPLICATION_ID_MASK; _appId = appId; + _encodedForm = null; } public String getClusterIdAsString() @@ -592,13 +637,14 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti public void setClusterId(String clusterId) { - setClusterId((clusterId == null) ? null : new AMQShortString(clusterId)); + setClusterId((clusterId == null) ? null : AMQShortString.valueOf(clusterId)); } public void setClusterId(AMQShortString clusterId) { _propertyFlags |= CLUSTER_ID_MASK; _clusterId = clusterId; + _encodedForm = null; } public String toString() diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java index f9580d82b1..554e9373d8 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java @@ -20,7 +20,8 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; +import org.apache.qpid.codec.MarkableDataInput; + import java.io.IOException; /** @@ -28,5 +29,5 @@ import java.io.IOException; */ public interface BodyFactory { - AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException; + AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ByteArrayDataInput.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ByteArrayDataInput.java new file mode 100644 index 0000000000..656185629b --- /dev/null +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ByteArrayDataInput.java @@ -0,0 +1,174 @@ +package org.apache.qpid.framing; + +import org.apache.qpid.codec.MarkableDataInput; + +import java.io.IOException; + +public class ByteArrayDataInput implements ExtendedDataInput, MarkableDataInput +{ + private byte[] _data; + private int _offset; + private int _length; + private int _origin; + private int _mark; + + public ByteArrayDataInput(byte[] data) + { + this(data,0, data.length); + } + + public ByteArrayDataInput(byte[] data, int offset, int length) + { + _data = data; + _offset = offset; + _length = length; + _origin = offset; + _mark = 0; + } + + public void readFully(byte[] b) + { + System.arraycopy(_data,_offset,b,0,b.length); + _offset+=b.length; + } + + public void readFully(byte[] b, int off, int len) + { + System.arraycopy(_data,_offset,b,off,len); + _offset+=len; + } + + public int skipBytes(int n) + { + return _offset+=n; + } + + public boolean readBoolean() + { + return _data[_offset++] != 0; + } + + public byte readByte() + { + return _data[_offset++]; + } + + public int readUnsignedByte() + { + return ((int)_data[_offset++]) & 0xFF; + } + + public short readShort() + { + return (short) (((((int)_data[_offset++]) << 8) & 0xFF00) | (((int)_data[_offset++]) & 0xFF)); + } + + public int readUnsignedShort() + { + return (((((int)_data[_offset++]) << 8) & 0xFF00) | (((int)_data[_offset++]) & 0xFF)); + } + + public char readChar() + { + return (char) (((((int)_data[_offset++]) << 8) & 0xFF00) | (((int)_data[_offset++]) & 0xFF)); + } + + public int readInt() + { + return ((((int)_data[_offset++]) << 24) & 0xFF000000) + | ((((int)_data[_offset++]) << 16) & 0xFF0000) + | ((((int)_data[_offset++]) << 8) & 0xFF00) + | (((int)_data[_offset++]) & 0xFF); + } + + public long readLong() + { + return ((((long)_data[_offset++]) << 56) & 0xFF00000000000000L) + | ((((long)_data[_offset++]) << 48) & 0xFF000000000000L) + | ((((long)_data[_offset++]) << 40) & 0xFF0000000000L) + | ((((long)_data[_offset++]) << 32) & 0xFF00000000L) + | ((((long)_data[_offset++]) << 24) & 0xFF000000L) + | ((((long)_data[_offset++]) << 16) & 0xFF0000L) + | ((((long)_data[_offset++]) << 8) & 0xFF00L) + | (((long)_data[_offset++]) & 0xFFL); + } + + public float readFloat() + { + return Float.intBitsToFloat(readInt()); + } + + public double readDouble() + { + return Double.longBitsToDouble(readLong()); + } + + public AMQShortString readAMQShortString() + { + int length = _data[_offset++] & 0xff; + if(length == 0) + { + return null; + } + else + { + final AMQShortString amqShortString = new AMQShortString(_data, _offset, length); + _offset+=length; + return amqShortString; + } + } + + public String readLine() + { + throw new UnsupportedOperationException(); + } + + public String readUTF() + { + throw new UnsupportedOperationException(); + } + + public int available() + { + return (_origin+_length)-_offset; + } + + + public long skip(long i) + { + _offset+=i; + return i; + } + + public int read(byte[] b) + { + readFully(b); + return b.length; + } + + public int position() + { + return _offset - _origin; + } + + public void position(int position) + { + _offset = position + _origin; + } + + public int length() + { + return _length; + } + + + public void mark(int readAhead) + { + _mark = _offset-_origin; + } + + public void reset() + { + _offset = _origin + _mark; + } +} diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java index 15bc20c52d..098e3652ad 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.framing; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; public class CompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQDataBlock @@ -50,7 +50,7 @@ public class CompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQD return frameSize; } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { for (int i = 0; i < _blocks.length; i++) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java index aedb35f92a..541d104dc9 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java @@ -20,9 +20,11 @@ */ package org.apache.qpid.framing; +import java.io.DataInput; import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; +import java.nio.ByteBuffer; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.AMQException; @@ -37,10 +39,10 @@ public class ContentBody implements AMQBody { } - public ContentBody(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException + public ContentBody(DataInput buffer, long size) throws AMQFrameDecodingException, IOException { _payload = new byte[(int)size]; - buffer.read(_payload); + buffer.readFully(_payload); } @@ -59,7 +61,7 @@ public class ContentBody implements AMQBody return _payload == null ? 0 : _payload.length; } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { buffer.write(_payload); } @@ -84,11 +86,62 @@ public class ContentBody implements AMQBody { } + private static class BufferContentBody implements AMQBody + { + private final int _length; + private final int _offset; + private final ByteBuffer _buf; + + private BufferContentBody( ByteBuffer buf, int offset, int length) + { + _length = length; + _offset = offset; + _buf = buf; + } + + public byte getFrameType() + { + return TYPE; + } + + + public int getSize() + { + return _length; + } + public void writePayload(DataOutput buffer) throws IOException + { + if(_buf.hasArray()) + { + buffer.write(_buf.array(), _buf.arrayOffset() + _offset, _length); + } + else + { + byte[] data = new byte[_length]; + ByteBuffer buf = _buf.duplicate(); + + buf.position(_offset); + buf.limit(_offset+_length); + buf.get(data); + buffer.write(data); + } + } + + + public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException + { + throw new RuntimeException("Buffered Body only to be used for outgoing data"); + } + } + + public static AMQFrame createAMQFrame(int channelId, ByteBuffer buf, int offset, int length) + { + return new AMQFrame(channelId, new BufferContentBody(buf, offset, length)); + } public static AMQFrame createAMQFrame(int channelId, ContentBody body) { - final AMQFrame frame = new AMQFrame(channelId, body); - return frame; + return new AMQFrame(channelId, body); } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java index a0b030ab6b..de2ffe9755 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; import java.io.IOException; +import org.apache.qpid.codec.MarkableDataInput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +42,7 @@ public class ContentBodyFactory implements BodyFactory _log.debug("Creating content body factory"); } - public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException + public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException { return new ContentBody(in, bodySize); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java index 18d0f26152..8a2ad53157 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java @@ -20,8 +20,9 @@ */ package org.apache.qpid.framing; +import java.io.DataInput; import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; @@ -45,7 +46,7 @@ public class ContentHeaderBody implements AMQBody { } - public ContentHeaderBody(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException + public ContentHeaderBody(DataInput buffer, long size) throws AMQFrameDecodingException, IOException { classId = buffer.readUnsignedShort(); weight = buffer.readUnsignedShort(); @@ -106,7 +107,7 @@ public class ContentHeaderBody implements AMQBody return 2 + 2 + 8 + 2 + properties.getPropertyListSize(); } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { EncodingUtils.writeUnsignedShort(buffer, classId); EncodingUtils.writeUnsignedShort(buffer, weight); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java index a474e337b7..c3e4c69ec0 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; import java.io.IOException; +import org.apache.qpid.codec.MarkableDataInput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +42,7 @@ public class ContentHeaderBodyFactory implements BodyFactory _log.debug("Creating content header body factory"); } - public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException + public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException { // all content headers are the same - it is only the properties that differ. // the content header body further delegates construction of properties diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java index 237929f9a3..ea8358a538 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java @@ -20,8 +20,9 @@ */ package org.apache.qpid.framing; +import java.io.DataInput; import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; @@ -35,7 +36,7 @@ public interface ContentHeaderProperties * Writes the property list to the buffer, in a suitably encoded form. * @param buffer The buffer to write to */ - void writePropertyListPayload(DataOutputStream buffer) throws IOException; + void writePropertyListPayload(DataOutput buffer) throws IOException; /** * Populates the properties from buffer. @@ -43,7 +44,7 @@ public interface ContentHeaderProperties * @param propertyFlags he property flags. * @throws AMQFrameDecodingException when the buffer does not contain valid data */ - void populatePropertiesFromBuffer(DataInputStream buffer, int propertyFlags, int size) + void populatePropertiesFromBuffer(DataInput buffer, int propertyFlags, int size) throws AMQFrameDecodingException, IOException; /** diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java index 43ee8cd1f1..48bd52858d 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.framing; +import java.io.DataInput; import java.io.DataInputStream; import java.io.IOException; @@ -39,7 +40,7 @@ public class ContentHeaderPropertiesFactory } public ContentHeaderProperties createContentHeaderProperties(int classId, int propertyFlags, - DataInputStream buffer, int size) + DataInput buffer, int size) throws AMQFrameDecodingException, IOException { ContentHeaderProperties properties; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java index 2d7e27405c..e018407509 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java @@ -219,7 +219,7 @@ public class EncodingUtils return 0; } - public static void writeShortStringBytes(DataOutputStream buffer, String s) throws IOException + public static void writeShortStringBytes(DataOutput buffer, String s) throws IOException { if (s != null) { @@ -243,7 +243,7 @@ public class EncodingUtils } } - public static void writeShortStringBytes(DataOutputStream buffer, AMQShortString s) throws IOException + public static void writeShortStringBytes(DataOutput buffer, AMQShortString s) throws IOException { if (s != null) { @@ -257,7 +257,7 @@ public class EncodingUtils } } - public static void writeLongStringBytes(DataOutputStream buffer, String s) throws IOException + public static void writeLongStringBytes(DataOutput buffer, String s) throws IOException { assert (s == null) || (s.length() <= 0xFFFE); if (s != null) @@ -279,7 +279,7 @@ public class EncodingUtils } } - public static void writeLongStringBytes(DataOutputStream buffer, char[] s) throws IOException + public static void writeLongStringBytes(DataOutput buffer, char[] s) throws IOException { assert (s == null) || (s.length <= 0xFFFE); if (s != null) @@ -300,7 +300,7 @@ public class EncodingUtils } } - public static void writeLongStringBytes(DataOutputStream buffer, byte[] bytes) throws IOException + public static void writeLongStringBytes(DataOutput buffer, byte[] bytes) throws IOException { assert (bytes == null) || (bytes.length <= 0xFFFE); if (bytes != null) @@ -314,13 +314,13 @@ public class EncodingUtils } } - public static void writeUnsignedByte(DataOutputStream buffer, short b) throws IOException + public static void writeUnsignedByte(DataOutput buffer, short b) throws IOException { byte bv = (byte) b; buffer.write(bv); } - public static void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException + public static void writeUnsignedShort(DataOutput buffer, int s) throws IOException { // TODO: Is this comparison safe? Do I need to cast RHS to long? if (s < Short.MAX_VALUE) @@ -340,7 +340,7 @@ public class EncodingUtils return 4; } - public static void writeUnsignedInteger(DataOutputStream buffer, long l) throws IOException + public static void writeUnsignedInteger(DataOutput buffer, long l) throws IOException { // TODO: Is this comparison safe? Do I need to cast RHS to long? if (l < Integer.MAX_VALUE) @@ -360,7 +360,7 @@ public class EncodingUtils } } - public static void writeFieldTableBytes(DataOutputStream buffer, FieldTable table) throws IOException + public static void writeFieldTableBytes(DataOutput buffer, FieldTable table) throws IOException { if (table != null) { @@ -372,12 +372,12 @@ public class EncodingUtils } } - public static void writeContentBytes(DataOutputStream buffer, Content content) + public static void writeContentBytes(DataOutput buffer, Content content) { // TODO: New Content class required for AMQP 0-9. } - public static void writeBooleans(DataOutputStream buffer, boolean[] values) throws IOException + public static void writeBooleans(DataOutput buffer, boolean[] values) throws IOException { byte packedValue = 0; for (int i = 0; i < values.length; i++) @@ -391,13 +391,13 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value) throws IOException + public static void writeBooleans(DataOutput buffer, boolean value) throws IOException { buffer.write(value ? (byte) 1 : (byte) 0); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1) throws IOException + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -409,7 +409,7 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2) throws IOException + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -426,7 +426,7 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3) throws IOException + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -448,7 +448,7 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3, + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3, boolean value4) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -476,7 +476,7 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3, + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3, boolean value4, boolean value5) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -509,7 +509,7 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3, + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3, boolean value4, boolean value5, boolean value6) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -547,7 +547,7 @@ public class EncodingUtils buffer.write(packedValue); } - public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3, + public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3, boolean value4, boolean value5, boolean value6, boolean value7) throws IOException { byte packedValue = value0 ? (byte) 1 : (byte) 0; @@ -596,7 +596,7 @@ public class EncodingUtils * @param buffer * @param data */ - public static void writeLongstr(DataOutputStream buffer, byte[] data) throws IOException + public static void writeLongstr(DataOutput buffer, byte[] data) throws IOException { if (data != null) { @@ -609,12 +609,12 @@ public class EncodingUtils } } - public static void writeTimestamp(DataOutputStream buffer, long timestamp) throws IOException + public static void writeTimestamp(DataOutput buffer, long timestamp) throws IOException { writeLong(buffer, timestamp); } - public static boolean[] readBooleans(DataInputStream buffer) throws IOException + public static boolean[] readBooleans(DataInput buffer) throws IOException { final byte packedValue = buffer.readByte(); if (packedValue == 0) @@ -641,7 +641,7 @@ public class EncodingUtils return result; } - public static FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException + public static FieldTable readFieldTable(DataInput buffer) throws AMQFrameDecodingException, IOException { long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL; if (length == 0) @@ -654,19 +654,19 @@ public class EncodingUtils } } - public static Content readContent(DataInputStream buffer) throws AMQFrameDecodingException + public static Content readContent(DataInput buffer) throws AMQFrameDecodingException { // TODO: New Content class required for AMQP 0-9. return null; } - public static AMQShortString readAMQShortString(DataInputStream buffer) throws IOException + public static AMQShortString readAMQShortString(DataInput buffer) throws IOException { return AMQShortString.readFromBuffer(buffer); } - public static String readShortString(DataInputStream buffer) throws IOException + public static String readShortString(DataInput buffer) throws IOException { short length = (short) (((short)buffer.readByte()) & 0xFF); if (length == 0) @@ -681,7 +681,7 @@ public class EncodingUtils // this approach here is valid since we know that all the chars are // ASCII (0-127) byte[] stringBytes = new byte[length]; - buffer.read(stringBytes, 0, length); + buffer.readFully(stringBytes, 0, length); char[] stringChars = new char[length]; for (int i = 0; i < stringChars.length; i++) { @@ -692,7 +692,7 @@ public class EncodingUtils } } - public static String readLongString(DataInputStream buffer) throws IOException + public static String readLongString(DataInput buffer) throws IOException { long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL; if (length == 0) @@ -707,7 +707,7 @@ public class EncodingUtils // this approach here is valid since we know that all the chars are // ASCII (0-127) byte[] stringBytes = new byte[(int) length]; - buffer.read(stringBytes, 0, (int) length); + buffer.readFully(stringBytes, 0, (int) length); char[] stringChars = new char[(int) length]; for (int i = 0; i < stringChars.length; i++) { @@ -718,7 +718,7 @@ public class EncodingUtils } } - public static byte[] readLongstr(DataInputStream buffer) throws IOException + public static byte[] readLongstr(DataInput buffer) throws IOException { long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL; if (length == 0) @@ -728,13 +728,13 @@ public class EncodingUtils else { byte[] result = new byte[(int) length]; - buffer.read(result); + buffer.readFully(result); return result; } } - public static long readTimestamp(DataInputStream buffer) throws IOException + public static long readTimestamp(DataInput buffer) throws IOException { // Discard msb from AMQ timestamp // buffer.getUnsignedInt(); @@ -818,12 +818,12 @@ public class EncodingUtils // AMQP_BOOLEAN_PROPERTY_PREFIX - public static void writeBoolean(DataOutputStream buffer, Boolean aBoolean) throws IOException + public static void writeBoolean(DataOutput buffer, boolean aBoolean) throws IOException { buffer.write(aBoolean ? 1 : 0); } - public static boolean readBoolean(DataInputStream buffer) throws IOException + public static boolean readBoolean(DataInput buffer) throws IOException { byte packedValue = buffer.readByte(); @@ -836,12 +836,12 @@ public class EncodingUtils } // AMQP_BYTE_PROPERTY_PREFIX - public static void writeByte(DataOutputStream buffer, Byte aByte) throws IOException + public static void writeByte(DataOutput buffer, byte aByte) throws IOException { buffer.writeByte(aByte); } - public static byte readByte(DataInputStream buffer) throws IOException + public static byte readByte(DataInput buffer) throws IOException { return buffer.readByte(); } @@ -852,12 +852,12 @@ public class EncodingUtils } // AMQP_SHORT_PROPERTY_PREFIX - public static void writeShort(DataOutputStream buffer, Short aShort) throws IOException + public static void writeShort(DataOutput buffer, short aShort) throws IOException { buffer.writeShort(aShort); } - public static short readShort(DataInputStream buffer) throws IOException + public static short readShort(DataInput buffer) throws IOException { return buffer.readShort(); } @@ -868,12 +868,12 @@ public class EncodingUtils } // INTEGER_PROPERTY_PREFIX - public static void writeInteger(DataOutputStream buffer, Integer aInteger) throws IOException + public static void writeInteger(DataOutput buffer, int aInteger) throws IOException { buffer.writeInt(aInteger); } - public static int readInteger(DataInputStream buffer) throws IOException + public static int readInteger(DataInput buffer) throws IOException { return buffer.readInt(); } @@ -884,12 +884,12 @@ public class EncodingUtils } // AMQP_LONG_PROPERTY_PREFIX - public static void writeLong(DataOutputStream buffer, Long aLong) throws IOException + public static void writeLong(DataOutput buffer, long aLong) throws IOException { buffer.writeLong(aLong); } - public static long readLong(DataInputStream buffer) throws IOException + public static long readLong(DataInput buffer) throws IOException { return buffer.readLong(); } @@ -900,12 +900,12 @@ public class EncodingUtils } // Float_PROPERTY_PREFIX - public static void writeFloat(DataOutputStream buffer, Float aFloat) throws IOException + public static void writeFloat(DataOutput buffer, float aFloat) throws IOException { buffer.writeFloat(aFloat); } - public static float readFloat(DataInputStream buffer) throws IOException + public static float readFloat(DataInput buffer) throws IOException { return buffer.readFloat(); } @@ -916,12 +916,12 @@ public class EncodingUtils } // Double_PROPERTY_PREFIX - public static void writeDouble(DataOutputStream buffer, Double aDouble) throws IOException + public static void writeDouble(DataOutput buffer, Double aDouble) throws IOException { buffer.writeDouble(aDouble); } - public static double readDouble(DataInputStream buffer) throws IOException + public static double readDouble(DataInput buffer) throws IOException { return buffer.readDouble(); } @@ -931,7 +931,7 @@ public class EncodingUtils return 8; } - public static byte[] readBytes(DataInputStream buffer) throws IOException + public static byte[] readBytes(DataInput buffer) throws IOException { long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL; if (length == 0) @@ -941,13 +941,13 @@ public class EncodingUtils else { byte[] dataBytes = new byte[(int)length]; - buffer.read(dataBytes, 0, (int) length); + buffer.readFully(dataBytes, 0, (int) length); return dataBytes; } } - public static void writeBytes(DataOutputStream buffer, byte[] data) throws IOException + public static void writeBytes(DataOutput buffer, byte[] data) throws IOException { if (data != null) { @@ -969,19 +969,19 @@ public class EncodingUtils return encodedByteLength(); } - public static char readChar(DataInputStream buffer) throws IOException + public static char readChar(DataInput buffer) throws IOException { // This is valid as we know that the Character is ASCII 0..127 - return (char) buffer.read(); + return (char) buffer.readByte(); } - public static void writeChar(DataOutputStream buffer, char character) throws IOException + public static void writeChar(DataOutput buffer, char character) throws IOException { // This is valid as we know that the Character is ASCII 0..127 writeByte(buffer, (byte) character); } - public static long readLongAsShortString(DataInputStream buffer) throws IOException + public static long readLongAsShortString(DataInput buffer) throws IOException { short length = (short) buffer.readUnsignedByte(); short pos = 0; @@ -1018,7 +1018,7 @@ public class EncodingUtils return result; } - public static long readUnsignedInteger(DataInputStream buffer) throws IOException + public static long readUnsignedInteger(DataInput buffer) throws IOException { long l = 0xFF & buffer.readByte(); l <<= 8; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ExtendedDataInput.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ExtendedDataInput.java new file mode 100644 index 0000000000..c789d9275e --- /dev/null +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ExtendedDataInput.java @@ -0,0 +1,14 @@ +package org.apache.qpid.framing; + +import java.io.DataInput; + +public interface ExtendedDataInput extends DataInput +{ + AMQShortString readAMQShortString(); + + int available(); + + int position(); + + void position(int position); +} 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 4a126b8504..863e363b87 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 @@ -25,11 +25,7 @@ import org.slf4j.LoggerFactory; import org.apache.qpid.AMQPInvalidClassException; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import java.io.*; import java.math.BigDecimal; import java.util.Collections; import java.util.Enumeration; @@ -44,18 +40,27 @@ import java.util.Set; public class FieldTable { private static final Logger _logger = LoggerFactory.getLogger(FieldTable.class); - private static final String STRICT_AMQP = "STRICT_AMQP"; - private final boolean _strictAMQP = Boolean.valueOf(System.getProperty(STRICT_AMQP, "false")); + private static final String STRICT_AMQP_NAME = "STRICT_AMQP"; + private static final boolean STRICT_AMQP = Boolean.valueOf(System.getProperty(STRICT_AMQP_NAME, "false")); private byte[] _encodedForm; + private int _encodedFormOffset; private LinkedHashMap<AMQShortString, AMQTypedValue> _properties = null; private long _encodedSize; private static final int INITIAL_HASHMAP_CAPACITY = 16; private static final int INITIAL_ENCODED_FORM_SIZE = 256; + private final boolean _strictAMQP; public FieldTable() { + this(STRICT_AMQP); + } + + + public FieldTable(boolean strictAMQP) + { super(); + _strictAMQP = strictAMQP; } /** @@ -64,14 +69,28 @@ public class FieldTable * @param buffer the buffer from which to read data. The length byte must be read already * @param length the length of the field table. Must be > 0. */ - public FieldTable(DataInputStream buffer, long length) throws IOException + public FieldTable(DataInput buffer, long length) throws IOException { this(); _encodedForm = new byte[(int) length]; - buffer.read(_encodedForm); + buffer.readFully(_encodedForm); _encodedSize = length; } + public FieldTable(byte[] encodedForm, int offset, int length) throws IOException + { + this(); + _encodedForm = encodedForm; + _encodedFormOffset = offset; + _encodedSize = length; + } + + + public boolean isClean() + { + return _encodedForm != null; + } + public AMQTypedValue getProperty(AMQShortString string) { checkPropertyName(string); @@ -181,7 +200,7 @@ public class FieldTable public Boolean getBoolean(String string) { - return getBoolean(new AMQShortString(string)); + return getBoolean(AMQShortString.valueOf(string)); } public Boolean getBoolean(AMQShortString string) @@ -199,7 +218,7 @@ public class FieldTable public Byte getByte(String string) { - return getByte(new AMQShortString(string)); + return getByte(AMQShortString.valueOf(string)); } public Byte getByte(AMQShortString string) @@ -217,7 +236,7 @@ public class FieldTable public Short getShort(String string) { - return getShort(new AMQShortString(string)); + return getShort(AMQShortString.valueOf(string)); } public Short getShort(AMQShortString string) @@ -235,7 +254,7 @@ public class FieldTable public Integer getInteger(String string) { - return getInteger(new AMQShortString(string)); + return getInteger(AMQShortString.valueOf(string)); } public Integer getInteger(AMQShortString string) @@ -253,7 +272,7 @@ public class FieldTable public Long getLong(String string) { - return getLong(new AMQShortString(string)); + return getLong(AMQShortString.valueOf(string)); } public Long getLong(AMQShortString string) @@ -271,7 +290,7 @@ public class FieldTable public Float getFloat(String string) { - return getFloat(new AMQShortString(string)); + return getFloat(AMQShortString.valueOf(string)); } public Float getFloat(AMQShortString string) @@ -289,7 +308,7 @@ public class FieldTable public Double getDouble(String string) { - return getDouble(new AMQShortString(string)); + return getDouble(AMQShortString.valueOf(string)); } public Double getDouble(AMQShortString string) @@ -307,7 +326,7 @@ public class FieldTable public String getString(String string) { - return getString(new AMQShortString(string)); + return getString(AMQShortString.valueOf(string)); } public String getString(AMQShortString string) @@ -330,7 +349,7 @@ public class FieldTable public Character getCharacter(String string) { - return getCharacter(new AMQShortString(string)); + return getCharacter(AMQShortString.valueOf(string)); } public Character getCharacter(AMQShortString string) @@ -348,7 +367,7 @@ public class FieldTable public byte[] getBytes(String string) { - return getBytes(new AMQShortString(string)); + return getBytes(AMQShortString.valueOf(string)); } public byte[] getBytes(AMQShortString string) @@ -374,7 +393,7 @@ public class FieldTable */ public FieldTable getFieldTable(String string) { - return getFieldTable(new AMQShortString(string)); + return getFieldTable(AMQShortString.valueOf(string)); } /** @@ -401,7 +420,7 @@ public class FieldTable public Object getObject(String string) { - return getObject(new AMQShortString(string)); + return getObject(AMQShortString.valueOf(string)); } public Object getObject(AMQShortString string) @@ -447,7 +466,7 @@ public class FieldTable // ************ Setters public Object setBoolean(String string, Boolean b) { - return setBoolean(new AMQShortString(string), b); + return setBoolean(AMQShortString.valueOf(string), b); } public Object setBoolean(AMQShortString string, Boolean b) @@ -457,7 +476,7 @@ public class FieldTable public Object setByte(String string, Byte b) { - return setByte(new AMQShortString(string), b); + return setByte(AMQShortString.valueOf(string), b); } public Object setByte(AMQShortString string, Byte b) @@ -467,7 +486,7 @@ public class FieldTable public Object setShort(String string, Short i) { - return setShort(new AMQShortString(string), i); + return setShort(AMQShortString.valueOf(string), i); } public Object setShort(AMQShortString string, Short i) @@ -475,29 +494,29 @@ public class FieldTable return setProperty(string, AMQType.SHORT.asTypedValue(i)); } - public Object setInteger(String string, Integer i) + public Object setInteger(String string, int i) { - return setInteger(new AMQShortString(string), i); + return setInteger(AMQShortString.valueOf(string), i); } - public Object setInteger(AMQShortString string, Integer i) + public Object setInteger(AMQShortString string, int i) { - return setProperty(string, AMQType.INT.asTypedValue(i)); + return setProperty(string, AMQTypedValue.createAMQTypedValue(i)); } - public Object setLong(String string, Long l) + public Object setLong(String string, long l) { - return setLong(new AMQShortString(string), l); + return setLong(AMQShortString.valueOf(string), l); } - public Object setLong(AMQShortString string, Long l) + public Object setLong(AMQShortString string, long l) { - return setProperty(string, AMQType.LONG.asTypedValue(l)); + return setProperty(string, AMQTypedValue.createAMQTypedValue(l)); } public Object setFloat(String string, Float f) { - return setFloat(new AMQShortString(string), f); + return setFloat(AMQShortString.valueOf(string), f); } public Object setFloat(AMQShortString string, Float v) @@ -507,7 +526,7 @@ public class FieldTable public Object setDouble(String string, Double d) { - return setDouble(new AMQShortString(string), d); + return setDouble(AMQShortString.valueOf(string), d); } public Object setDouble(AMQShortString string, Double v) @@ -517,7 +536,7 @@ public class FieldTable public Object setString(String string, String s) { - return setString(new AMQShortString(string), s); + return setString(AMQShortString.valueOf(string), s); } public Object setAsciiString(AMQShortString string, String value) @@ -546,7 +565,7 @@ public class FieldTable public Object setChar(String string, char c) { - return setChar(new AMQShortString(string), c); + return setChar(AMQShortString.valueOf(string), c); } public Object setChar(AMQShortString string, char c) @@ -556,7 +575,7 @@ public class FieldTable public Object setBytes(String string, byte[] b) { - return setBytes(new AMQShortString(string), b); + return setBytes(AMQShortString.valueOf(string), b); } public Object setBytes(AMQShortString string, byte[] bytes) @@ -566,7 +585,7 @@ public class FieldTable public Object setBytes(String string, byte[] bytes, int start, int length) { - return setBytes(new AMQShortString(string), bytes, start, length); + return setBytes(AMQShortString.valueOf(string), bytes, start, length); } public Object setBytes(AMQShortString string, byte[] bytes, int start, int length) @@ -579,7 +598,7 @@ public class FieldTable public Object setObject(String string, Object o) { - return setObject(new AMQShortString(string), o); + return setObject(AMQShortString.valueOf(string), o); } public Object setTimestamp(AMQShortString string, long datetime) @@ -617,7 +636,7 @@ public class FieldTable */ public Object setFieldTable(String string, FieldTable ftValue) { - return setFieldTable(new AMQShortString(string), ftValue); + return setFieldTable(AMQShortString.valueOf(string), ftValue); } /** @@ -681,7 +700,7 @@ public class FieldTable public boolean isNullStringValue(String name) { - AMQTypedValue value = getProperty(new AMQShortString(name)); + AMQTypedValue value = getProperty(AMQShortString.valueOf(name)); return (value != null) && (value.getType() == AMQType.VOID); } @@ -713,7 +732,7 @@ public class FieldTable public boolean itemExists(String string) { - return itemExists(new AMQShortString(string)); + return itemExists(AMQShortString.valueOf(string)); } public String toString() @@ -769,7 +788,7 @@ public class FieldTable // ************************* Byte Buffer Processing - public void writeToBuffer(DataOutputStream buffer) throws IOException + public void writeToBuffer(DataOutput buffer) throws IOException { final boolean trace = _logger.isDebugEnabled(); @@ -919,7 +938,7 @@ public class FieldTable public boolean containsKey(String key) { - return containsKey(new AMQShortString(key)); + return containsKey(AMQShortString.valueOf(key)); } public Set<String> keys() @@ -942,7 +961,7 @@ public class FieldTable public Object get(String key) { - return get(new AMQShortString(key)); + return get(AMQShortString.valueOf(key)); } public Object get(AMQShortString key) @@ -958,7 +977,7 @@ public class FieldTable public Object remove(String key) { - return remove(new AMQShortString(key)); + return remove(AMQShortString.valueOf(key)); } @@ -1005,12 +1024,12 @@ public class FieldTable return _properties.keySet(); } - private void putDataInBuffer(DataOutputStream buffer) throws IOException + private void putDataInBuffer(DataOutput buffer) throws IOException { if (_encodedForm != null) { - buffer.write(_encodedForm); + buffer.write(_encodedForm,_encodedFormOffset,(int)_encodedSize); } else if (_properties != null) { @@ -1039,9 +1058,8 @@ public class FieldTable private void setFromBuffer() throws AMQFrameDecodingException, IOException { - final ByteArrayInputStream in = new ByteArrayInputStream(_encodedForm); - DataInputStream buffer = new DataInputStream(in); - final boolean trace = _logger.isDebugEnabled(); + ByteArrayDataInput baid = new ByteArrayDataInput(_encodedForm, _encodedFormOffset, (int)_encodedSize); + if (_encodedSize > 0) { @@ -1051,12 +1069,12 @@ public class FieldTable do { - final AMQShortString key = EncodingUtils.readAMQShortString(buffer); - AMQTypedValue value = AMQTypedValue.readFromBuffer(buffer); + final AMQShortString key = baid.readAMQShortString(); + AMQTypedValue value = AMQTypedValue.readFromBuffer(baid); _properties.put(key, value); } - while (in.available() > 0); + while (baid.available() > 0); } @@ -1101,7 +1119,7 @@ public class FieldTable FieldTable table = new FieldTable(); for(Map.Entry<String,Object> entry : map.entrySet()) { - table.put(new AMQShortString(entry.getKey()), entry.getValue()); + table.put(AMQShortString.valueOf(entry.getKey()), entry.getValue()); } return table; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java index 438a46f28b..af0c5b845c 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.framing; +import java.io.DataInput; import java.io.DataInputStream; import java.io.IOException; @@ -30,7 +31,7 @@ public class FieldTableFactory return new FieldTable(); } - public static FieldTable newFieldTable(DataInputStream byteBuffer, long length) throws AMQFrameDecodingException, IOException + public static FieldTable newFieldTable(DataInput byteBuffer, long length) throws AMQFrameDecodingException, IOException { return new FieldTable(byteBuffer, length); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java index a6ce721a50..95b6246717 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java @@ -21,7 +21,7 @@ package org.apache.qpid.framing; import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; @@ -56,7 +56,7 @@ public class HeartbeatBody implements AMQBody return 0;//heartbeats we generate have no payload } - public void writePayload(DataOutputStream buffer) + public void writePayload(DataOutput buffer) { } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java index dfc49c6167..971caca41a 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java @@ -20,12 +20,13 @@ */ package org.apache.qpid.framing; -import java.io.DataInputStream; +import org.apache.qpid.codec.MarkableDataInput; public class HeartbeatBodyFactory implements BodyFactory { - public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException + public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException { return new HeartbeatBody(); } + } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java index 8c018316f0..2925724dc2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java @@ -21,13 +21,10 @@ package org.apache.qpid.framing; import org.apache.qpid.AMQException; +import org.apache.qpid.codec.MarkableDataInput; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import java.io.*; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; import java.util.Arrays; public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQDataBlock @@ -66,7 +63,7 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData pv.equals(ProtocolVersion.v0_91) ? 1 : pv.getMinorVersion()); } - public ProtocolInitiation(DataInputStream in) throws IOException + public ProtocolInitiation(MarkableDataInput in) throws IOException { _protocolHeader = new byte[4]; in.read(_protocolHeader); @@ -82,7 +79,7 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData return 4 + 1 + 1 + 1 + 1; } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { buffer.write(_protocolHeader); @@ -143,7 +140,7 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData * @return true if we have enough data to decode the PI frame fully, false if more * data is required */ - public boolean decodable(DataInputStream in) throws IOException + public boolean decodable(MarkableDataInput in) throws IOException { return (in.available() >= 8); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java index d2925d13a8..dd854dd498 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java @@ -21,7 +21,7 @@ package org.apache.qpid.framing; -import java.io.DataOutputStream; +import java.io.DataOutput; import java.io.IOException; public class SmallCompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQDataBlock @@ -69,7 +69,7 @@ public class SmallCompositeAMQDataBlock extends AMQDataBlock implements Encodabl return frameSize; } - public void writePayload(DataOutputStream buffer) throws IOException + public void writePayload(DataOutput buffer) throws IOException { if (_firstFrame != null) { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java index ed9136f7c9..e770fdd7e4 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java @@ -23,6 +23,7 @@ package org.apache.qpid.framing; import java.io.DataInputStream; import java.io.IOException; +import org.apache.qpid.codec.MarkableDataInput; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.slf4j.Logger; @@ -145,7 +146,7 @@ public class VersionSpecificRegistry } - public AMQMethodBody get(short classID, short methodID, DataInputStream in, long size) throws AMQFrameDecodingException, IOException + public AMQMethodBody get(short classID, short methodID, MarkableDataInput in, long size) throws AMQFrameDecodingException, IOException { AMQMethodBodyInstanceFactory bodyFactory; try diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java deleted file mode 100644 index 8de0f93ce9..0000000000 --- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java +++ /dev/null @@ -1,432 +0,0 @@ -package org.apache.qpid.pool; - -import java.util.AbstractQueue; -import java.util.Iterator; -import java.util.Collection; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.atomic.AtomicInteger; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public class ReadWriteJobQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable> -{ - - private final AtomicInteger _count = new AtomicInteger(0); - - private final ReentrantLock _takeLock = new ReentrantLock(); - - private final Condition _notEmpty = _takeLock.newCondition(); - - private final ReentrantLock _putLock = new ReentrantLock(); - - private final ConcurrentLinkedQueue<ReadWriteRunnable> _readJobQueue = new ConcurrentLinkedQueue<ReadWriteRunnable>(); - - private final ConcurrentLinkedQueue<ReadWriteRunnable> _writeJobQueue = new ConcurrentLinkedQueue<ReadWriteRunnable>(); - - - private class ReadWriteJobIterator implements Iterator<Runnable> - { - - private boolean _onReads; - private Iterator<ReadWriteRunnable> _iter = _writeJobQueue.iterator(); - - public boolean hasNext() - { - if(!_iter.hasNext()) - { - if(_onReads) - { - _iter = _readJobQueue.iterator(); - _onReads = true; - return _iter.hasNext(); - } - else - { - return false; - } - } - else - { - return true; - } - } - - public Runnable next() - { - if(_iter.hasNext()) - { - return _iter.next(); - } - else - { - return null; - } - } - - public void remove() - { - _takeLock.lock(); - try - { - _iter.remove(); - _count.decrementAndGet(); - } - finally - { - _takeLock.unlock(); - } - } - } - - public Iterator<Runnable> iterator() - { - return new ReadWriteJobIterator(); - } - - public int size() - { - return _count.get(); - } - - public boolean offer(final Runnable runnable) - { - final ReadWriteRunnable job = (ReadWriteRunnable) runnable; - final ReentrantLock putLock = _putLock; - putLock.lock(); - try - { - if(job.isRead()) - { - _readJobQueue.offer(job); - } - else - { - _writeJobQueue.offer(job); - } - if(_count.getAndIncrement() == 0) - { - _takeLock.lock(); - try - { - _notEmpty.signal(); - } - finally - { - _takeLock.unlock(); - } - } - return true; - } - finally - { - putLock.unlock(); - } - } - - public void put(final Runnable runnable) throws InterruptedException - { - final ReadWriteRunnable job = (ReadWriteRunnable) runnable; - final ReentrantLock putLock = _putLock; - putLock.lock(); - - try - { - if(job.isRead()) - { - _readJobQueue.offer(job); - } - else - { - _writeJobQueue.offer(job); - } - if(_count.getAndIncrement() == 0) - { - _takeLock.lock(); - try - { - _notEmpty.signal(); - } - finally - { - _takeLock.unlock(); - } - } - - } - finally - { - putLock.unlock(); - } - } - - - - public boolean offer(final Runnable runnable, final long timeout, final TimeUnit unit) throws InterruptedException - { - final ReadWriteRunnable job = (ReadWriteRunnable) runnable; - final ReentrantLock putLock = _putLock; - putLock.lock(); - - try - { - if(job.isRead()) - { - _readJobQueue.offer(job); - } - else - { - _writeJobQueue.offer(job); - } - if(_count.getAndIncrement() == 0) - { - _takeLock.lock(); - try - { - _notEmpty.signal(); - } - finally - { - _takeLock.unlock(); - } - } - - return true; - } - finally - { - putLock.unlock(); - } - - } - - public Runnable take() throws InterruptedException - { - final ReentrantLock takeLock = _takeLock; - takeLock.lockInterruptibly(); - try - { - try - { - while (_count.get() == 0) - { - _notEmpty.await(); - } - } - catch (InterruptedException ie) - { - _notEmpty.signal(); - throw ie; - } - - ReadWriteRunnable job = _writeJobQueue.poll(); - if(job == null) - { - job = _readJobQueue.poll(); - } - int c = _count.getAndDecrement(); - if (c > 1) - { - _notEmpty.signal(); - } - return job; - } - finally - { - takeLock.unlock(); - } - - - } - - public Runnable poll(final long timeout, final TimeUnit unit) throws InterruptedException - { - final ReentrantLock takeLock = _takeLock; - final AtomicInteger count = _count; - long nanos = unit.toNanos(timeout); - takeLock.lockInterruptibly(); - ReadWriteRunnable job = null; - try - { - - for (;;) - { - if (count.get() > 0) - { - job = _writeJobQueue.poll(); - if(job == null) - { - job = _readJobQueue.poll(); - } - int c = count.getAndDecrement(); - if (c > 1) - { - _notEmpty.signal(); - } - break; - } - if (nanos <= 0) - { - return null; - } - try - { - nanos = _notEmpty.awaitNanos(nanos); - } - catch (InterruptedException ie) - { - _notEmpty.signal(); - throw ie; - } - } - } - finally - { - takeLock.unlock(); - } - - return job; - } - - public int remainingCapacity() - { - return Integer.MAX_VALUE; - } - - public int drainTo(final Collection<? super Runnable> c) - { - int total = 0; - - _putLock.lock(); - _takeLock.lock(); - try - { - ReadWriteRunnable job; - while((job = _writeJobQueue.peek())!= null) - { - c.add(job); - _writeJobQueue.poll(); - _count.decrementAndGet(); - total++; - } - - while((job = _readJobQueue.peek())!= null) - { - c.add(job); - _readJobQueue.poll(); - _count.decrementAndGet(); - total++; - } - - } - finally - { - _takeLock.unlock(); - _putLock.unlock(); - } - return total; - } - - public int drainTo(final Collection<? super Runnable> c, final int maxElements) - { - int total = 0; - - _putLock.lock(); - _takeLock.lock(); - try - { - ReadWriteRunnable job; - while(total<=maxElements && (job = _writeJobQueue.peek())!= null) - { - c.add(job); - _writeJobQueue.poll(); - _count.decrementAndGet(); - total++; - } - - while(total<=maxElements && (job = _readJobQueue.peek())!= null) - { - c.add(job); - _readJobQueue.poll(); - _count.decrementAndGet(); - total++; - } - - } - finally - { - _takeLock.unlock(); - _putLock.unlock(); - } - return total; - - } - - public Runnable poll() - { - final ReentrantLock takeLock = _takeLock; - takeLock.lock(); - try - { - if(_count.get() > 0) - { - ReadWriteRunnable job = _writeJobQueue.poll(); - if(job == null) - { - job = _readJobQueue.poll(); - } - _count.decrementAndGet(); - return job; - } - else - { - return null; - } - } - finally - { - takeLock.unlock(); - } - - } - - public Runnable peek() - { - final ReentrantLock takeLock = _takeLock; - takeLock.lock(); - try - { - ReadWriteRunnable job = _writeJobQueue.peek(); - if(job == null) - { - job = _readJobQueue.peek(); - } - return job; - } - finally - { - takeLock.unlock(); - } - } -} diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java deleted file mode 100644 index 140c93ca8d..0000000000 --- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.apache.qpid.pool; - -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -public interface ReadWriteRunnable extends Runnable -{ - boolean isRead(); -} diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java index 8152a1f5e9..3e99b244c4 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java @@ -96,8 +96,6 @@ public class ReferenceCountingExecutorService */ private ThreadFactory _threadFactory = Executors.defaultThreadFactory(); - private final boolean _useBiasedPool = Boolean.getBoolean("org.apache.qpid.use_write_biased_pool"); - /** * Retrieves the singleton instance of this reference counter. * @@ -125,26 +123,12 @@ public class ReferenceCountingExecutorService { if (_refCount++ == 0) { - // Use a job queue that biases to writes - if(_useBiasedPool) - { - _pool = new ThreadPoolExecutor(_poolSize, _poolSize, - 0L, TimeUnit.MILLISECONDS, - new ReadWriteJobQueue(), - _threadFactory); - - } - else - { - _pool = new ThreadPoolExecutor(_poolSize, _poolSize, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<Runnable>(), - _threadFactory); - } - + _pool = new ThreadPoolExecutor(_poolSize, _poolSize, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), + _threadFactory); } - return _pool; } } 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 b78433052c..dee5f696b9 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 @@ -383,13 +383,19 @@ public class Connection extends ConnectionInvoker public void received(ProtocolEvent event) { - log.debug("RECV: [%s] %s", this, event); + if(log.isDebugEnabled()) + { + log.debug("RECV: [%s] %s", this, event); + } event.delegate(this, delegate); } public void send(ProtocolEvent event) { - log.debug("SEND: [%s] %s", this, event); + if(log.isDebugEnabled()) + { + log.debug("SEND: [%s] %s", this, event); + } Sender s = sender; if (s == null) { @@ -400,8 +406,15 @@ public class Connection extends ConnectionInvoker public void flush() { - log.debug("FLUSH: [%s]", this); - sender.flush(); + if(log.isDebugEnabled()) + { + log.debug("FLUSH: [%s]", this); + } + final Sender<ProtocolEvent> theSender = sender; + if(theSender != null) + { + theSender.flush(); + } } protected void invoke(Method method) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java index 9439e5e0de..543856ca39 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java @@ -20,13 +20,7 @@ */ package org.apache.qpid.transport; -import org.apache.qpid.transport.network.Frame; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.LinkedHashMap; -import java.nio.ByteBuffer; +import java.util.*; /** @@ -35,45 +29,87 @@ import java.nio.ByteBuffer; * @author Rafael H. Schloming */ -public class Header { +public class Header +{ - private final Struct[] structs; + private final DeliveryProperties _deliveryProps; + private final MessageProperties _messageProps; + private final List<Struct> _nonStandardProps; - public Header(List<Struct> structs) + public Header(DeliveryProperties deliveryProps, MessageProperties messageProps) { - this(structs.toArray(new Struct[structs.size()])); + this(deliveryProps, messageProps, null); } - public Header(Struct ... structs) + public Header(DeliveryProperties deliveryProps, MessageProperties messageProps, List<Struct> nonStandardProps) { - this.structs = structs; + _deliveryProps = deliveryProps; + _messageProps = messageProps; + _nonStandardProps = nonStandardProps; } public Struct[] getStructs() { + int size = 0; + if(_deliveryProps != null) + { + size++; + } + if(_messageProps != null) + { + size++; + } + if(_nonStandardProps != null) + { + size+=_nonStandardProps.size(); + } + Struct[] structs = new Struct[size]; + int index = 0; + if(_deliveryProps != null) + { + structs[index++] = _deliveryProps; + } + if(_messageProps != null) + { + structs[index++] = _messageProps; + } + if(_nonStandardProps != null) + { + for(Struct struct : _nonStandardProps) + { + structs[index++] = struct; + } + } + return structs; } + public DeliveryProperties getDeliveryProperties() + { + return _deliveryProps; + } - public <T> T get(Class<T> klass) + public MessageProperties getMessageProperties() { - for (Struct st : structs) - { - if (klass.isInstance(st)) - { - return (T) st; - } - } + return _messageProps; + } - return null; + public List<Struct> getNonStandardProperties() + { + return _nonStandardProps; } public String toString() { - StringBuffer str = new StringBuffer(); + StringBuilder str = new StringBuilder(); str.append(" Header("); boolean first = true; - for (Struct s : structs) + if(_deliveryProps !=null) + { + first=false; + str.append(_deliveryProps); + } + if(_messageProps != null) { if (first) { @@ -83,9 +119,24 @@ public class Header { { str.append(", "); } - str.append(s); + str.append(_messageProps); + } + if(_nonStandardProps != null) + { + for (Struct s : _nonStandardProps) + { + if (first) + { + first = false; + } + else + { + str.append(", "); + } + str.append(s); + } } - str.append(")"); + str.append(')'); return str.toString(); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java index f4335dc8a6..c47171dc4b 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java @@ -21,6 +21,8 @@ package org.apache.qpid.transport; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import static org.apache.qpid.util.Serial.*; @@ -32,94 +34,265 @@ import static org.apache.qpid.util.Serial.*; * @author Rafael H. Schloming */ -public final class Range +public abstract class Range implements RangeSet { - private final int lower; - private final int upper; + public static Range newInstance(int point) + { + return new PointImpl(point); + } + + public static Range newInstance(int lower, int upper) + { + return lower == upper ? new PointImpl(lower) : new RangeImpl(lower, upper); + } + + public abstract int getLower(); + + public abstract int getUpper(); + + public abstract boolean includes(int value); + + public abstract boolean includes(Range range); + + public abstract boolean intersects(Range range); + + public abstract boolean touches(Range range); + + public abstract Range span(Range range); + + public abstract List<Range> subtract(Range range); - public Range(int lower, int upper) + + public Range intersect(Range range) { - this.lower = lower; - this.upper = upper; + int l = max(getLower(), range.getLower()); + int r = min(getUpper(), range.getUpper()); + if (gt(l, r)) + { + return null; + } + else + { + return newInstance(l, r); + } } - public int getLower() + + + public int size() { - return lower; + return 1; } - public int getUpper() + public Iterator<Range> iterator() { - return upper; + return new RangeIterator(); } - public boolean includes(int value) + public Range getFirst() { - return le(lower, value) && le(value, upper); + return this; } - public boolean includes(Range range) + public Range getLast() { - return includes(range.lower) && includes(range.upper); + return this; } - public boolean intersects(Range range) + public void add(Range range) { - return (includes(range.lower) || includes(range.upper) || - range.includes(lower) || range.includes(upper)); + throw new UnsupportedOperationException(); } - public boolean touches(Range range) + public void add(int lower, int upper) { - return (intersects(range) || - includes(range.upper + 1) || includes(range.lower - 1) || - range.includes(upper + 1) || range.includes(lower - 1)); + throw new UnsupportedOperationException(); } - public Range span(Range range) + public void add(int value) { - return new Range(min(lower, range.lower), max(upper, range.upper)); + throw new UnsupportedOperationException(); } - public List<Range> subtract(Range range) + public void clear() { - List<Range> result = new ArrayList<Range>(); + throw new UnsupportedOperationException(); + } - if (includes(range.lower) && le(lower, range.lower - 1)) + public RangeSet copy() + { + RangeSet rangeSet = RangeSetFactory.createRangeSet(); + rangeSet.add(this); + return rangeSet; + } + + private static class PointImpl extends Range + { + private final int point; + + private PointImpl(int point) + { + this.point = point; + } + + public int getLower() { - result.add(new Range(lower, range.lower - 1)); + return point; } - if (includes(range.upper) && le(range.upper + 1, upper)) + public int getUpper() { - result.add(new Range(range.upper + 1, upper)); + return point; } - if (result.isEmpty() && !range.includes(this)) + public boolean includes(int value) { - result.add(this); + return value == point; } - return result; + + public boolean includes(Range range) + { + return range.getLower() == point && range.getUpper() == point; + } + + public boolean intersects(Range range) + { + return range.includes(point); + } + + public boolean touches(Range range) + { + return intersects(range) || + includes(range.getUpper() + 1) || includes(range.getLower() - 1) || + range.includes(point + 1) || range.includes(point - 1); + } + + public Range span(Range range) + { + return newInstance(min(point, range.getLower()), max(point, range.getUpper())); + } + + public List<Range> subtract(Range range) + { + if(range.includes(point)) + { + return Collections.emptyList(); + } + else + { + return Collections.singletonList((Range) this); + } + } + + public String toString() + { + return "[" + point + ", " + point + "]"; + } + + } - public Range intersect(Range range) + private static class RangeImpl extends Range { - int l = max(lower, range.lower); - int r = min(upper, range.upper); - if (gt(l, r)) + private final int lower; + private final int upper; + + private RangeImpl(int lower, int upper) { - return null; + this.lower = lower; + this.upper = upper; } - else + + public int getLower() + { + return lower; + } + + public int getUpper() + { + return upper; + } + + public boolean includes(int value) + { + return le(lower, value) && le(value, upper); + } + + public boolean includes(Range range) + { + return includes(range.getLower()) && includes(range.getUpper()); + } + + public boolean intersects(Range range) + { + return (includes(range.getLower()) || includes(range.getUpper()) || + range.includes(lower) || range.includes(upper)); + } + + public boolean touches(Range range) + { + return (intersects(range) || + includes(range.getUpper() + 1) || includes(range.getLower() - 1) || + range.includes(upper + 1) || range.includes(lower - 1)); + } + + public Range span(Range range) { - return new Range(l, r); + return newInstance(min(lower, range.getLower()), max(upper, range.getUpper())); + } + + public List<Range> subtract(Range range) + { + List<Range> result = new ArrayList<Range>(); + + if (includes(range.getLower()) && le(lower, range.getLower() - 1)) + { + result.add(newInstance(lower, range.getLower() - 1)); + } + + if (includes(range.getUpper()) && le(range.getUpper() + 1, upper)) + { + result.add(newInstance(range.getUpper() + 1, upper)); + } + + if (result.isEmpty() && !range.includes(this)) + { + result.add(this); + } + + return result; + } + + + public String toString() + { + return "[" + lower + ", " + upper + "]"; } } - public String toString() + + private class RangeIterator implements Iterator<Range> { - return "[" + lower + ", " + upper + "]"; - } + private boolean atFirst = true; + + public boolean hasNext() + { + return atFirst; + } + + public Range next() + { + Range range = atFirst ? Range.this : null; + atFirst = false; + return range; + } + + + public void remove() + { + throw new UnsupportedOperationException(); + } + } } 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 3850dc162b..34ebd02777 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 @@ -20,9 +20,7 @@ */ package org.apache.qpid.transport; -import java.util.Iterator; -import java.util.ListIterator; -import java.util.LinkedList; +import java.util.*; import static org.apache.qpid.util.Serial.*; @@ -32,121 +30,29 @@ import static org.apache.qpid.util.Serial.*; * @author Rafael H. Schloming */ -public final class RangeSet implements Iterable<Range> +public interface RangeSet extends Iterable<Range> { - private LinkedList<Range> ranges = new LinkedList<Range>(); - - public int size() - { - return ranges.size(); - } - - public Iterator<Range> iterator() - { - return ranges.iterator(); - } - - public Range getFirst() - { - return ranges.getFirst(); - } - - public Range getLast() - { - return ranges.getLast(); - } - - public boolean includes(Range range) - { - for (Range r : this) - { - if (r.includes(range)) - { - return true; - } - } - - return false; - } - - public boolean includes(int n) - { - for (Range r : this) - { - if (r.includes(n)) - { - return true; - } - } - - return false; - } - - public void add(Range range) - { - ListIterator<Range> it = ranges.listIterator(); - - while (it.hasNext()) - { - Range next = it.next(); - if (range.touches(next)) - { - it.remove(); - range = range.span(next); - } - else if (lt(range.getUpper(), next.getLower())) - { - it.previous(); - it.add(range); - return; - } - } - - it.add(range); - } - - public void add(int lower, int upper) - { - add(new Range(lower, upper)); - } - - public void add(int value) - { - add(value, value); - } - - public void clear() - { - ranges.clear(); - } - - public RangeSet copy() - { - RangeSet copy = new RangeSet(); - copy.ranges.addAll(ranges); - return copy; - } - - public String toString() - { - StringBuffer str = new StringBuffer(); - str.append("{"); - boolean first = true; - for (Range range : ranges) - { - if (first) - { - first = false; - } - else - { - str.append(", "); - } - str.append(range); - } - str.append("}"); - return str.toString(); - } + int size(); + + Iterator<Range> iterator(); + + Range getFirst(); + + Range getLast(); + + boolean includes(Range range); + + boolean includes(int n); + + void add(Range range); + + void add(int lower, int upper); + + void add(int value); + + void clear(); + + RangeSet copy(); } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/BooleanExpression.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetFactory.java index 14a5c7ea87..0f19d7e2b2 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/filter/BooleanExpression.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetFactory.java @@ -1,33 +1,34 @@ -/* Licensed to the Apache Software Foundation (ASF) under one +/* + * + * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * */ -package org.apache.qpid.filter; +package org.apache.qpid.transport; -import org.apache.qpid.AMQInternalException; -import org.apache.qpid.client.message.AbstractJMSMessage; - - -/** - * A BooleanExpression is an expression that always - * produces a Boolean result. - */ -public interface BooleanExpression extends Expression +public class RangeSetFactory { + public static RangeSet createRangeSet() + { + return new RangeSetImpl(); + } - public boolean matches(AbstractJMSMessage message) throws AMQInternalException; - + public static RangeSet createRangeSet(int size) + { + return new RangeSetImpl(size); + } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetImpl.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetImpl.java new file mode 100644 index 0000000000..f2540afb40 --- /dev/null +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetImpl.java @@ -0,0 +1,178 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.transport; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import static org.apache.qpid.util.Serial.lt; + +public class RangeSetImpl implements RangeSet +{ + + private List<Range> ranges; + + public RangeSetImpl() + { + ranges = new ArrayList<Range>(); + } + + public RangeSetImpl(int size) + { + ranges = new ArrayList<Range>(size); + } + + + public RangeSetImpl(org.apache.qpid.transport.RangeSetImpl copy) + { + ranges = new ArrayList<Range>(copy.ranges); + } + + public int size() + { + return ranges.size(); + } + + public Iterator<Range> iterator() + { + return ranges.iterator(); + } + + public Range getFirst() + { + return ranges.get(0); + } + + public Range getLast() + { + return ranges.get(ranges.size() - 1); + } + + public boolean includes(Range range) + { + for (Range r : this) + { + if (r.includes(range)) + { + return true; + } + } + + return false; + } + + public boolean includes(int n) + { + for (Range r : this) + { + if (r.includes(n)) + { + return true; + } + } + + return false; + } + + public void add(Range range) + { + ListIterator<Range> it = ranges.listIterator(); + + while (it.hasNext()) + { + Range next = it.next(); + if (range.touches(next)) + { + it.remove(); + range = range.span(next); + } + else if (lt(range.getUpper(), next.getLower())) + { + it.previous(); + it.add(range); + return; + } + } + + it.add(range); + } + + public void add(int lower, int upper) + { + switch(ranges.size()) + { + case 0: + ranges.add(Range.newInstance(lower, upper)); + break; + + case 1: + Range first = ranges.get(0); + if(first.getUpper() + 1 >= lower && upper >= first.getUpper()) + { + ranges.set(0, Range.newInstance(first.getLower(), upper)); + break; + } + + default: + add(Range.newInstance(lower, upper)); + } + + + } + + public void add(int value) + { + add(value, value); + } + + public void clear() + { + ranges.clear(); + } + + public RangeSet copy() + { + return new org.apache.qpid.transport.RangeSetImpl(this); + } + + public String toString() + { + StringBuffer str = new StringBuffer(); + str.append("{"); + boolean first = true; + for (Range range : ranges) + { + if (first) + { + first = false; + } + else + { + str.append(", "); + } + str.append(range); + } + str.append("}"); + return str.toString(); + } +} 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 321e5256b2..5a9ea73cae 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 @@ -44,6 +44,7 @@ import static org.apache.qpid.util.Serial.max; import static org.apache.qpid.util.Strings.toUTF8; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -61,7 +62,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class Session extends SessionInvoker { private static final Logger log = Logger.get(Session.class); - + public enum State { NEW, DETACHED, RESUMING, OPEN, CLOSING, CLOSED } static class DefaultSessionListener implements SessionListener @@ -96,6 +97,9 @@ public class Session extends SessionInvoker private final long timeout = Long.getLong(ClientProperties.QPID_SYNC_OP_TIMEOUT, Long.getLong(ClientProperties.AMQJ_DEFAULT_SYNCWRITE_TIMEOUT, ClientProperties.DEFAULT_SYNC_OPERATION_TIMEOUT)); + private final long blockedSendTimeout = Long.getLong("qpid.flow_control_wait_failure", timeout); + private long blockedSendReportingPeriod = Long.getLong("qpid.flow_control_wait_notify_period",5000L); + private boolean autoSync = false; private boolean incomingInit; @@ -228,10 +232,21 @@ public class Session extends SessionInvoker { try { - if (!credit.tryAcquire(timeout, TimeUnit.MILLISECONDS)) + long wait = blockedSendTimeout > blockedSendReportingPeriod ? blockedSendReportingPeriod : + blockedSendTimeout; + long totalWait = 1L; + while(totalWait <= blockedSendTimeout && !credit.tryAcquire(wait, TimeUnit.MILLISECONDS)) { + totalWait+=wait; + log.warn("Message send delayed by " + (totalWait)/1000 + "s due to broker enforced flow control"); + + + } + if(totalWait > blockedSendTimeout) + { + log.error("Message send failed due to timeout waiting on broker enforced flow control"); throw new SessionException - ("timed out waiting for message credit"); + ("timed out waiting for message credit"); } } catch (InterruptedException e) @@ -247,7 +262,7 @@ public class Session extends SessionInvoker synchronized (processedLock) { incomingInit = false; - processed = new RangeSet(); + processed = RangeSetFactory.createRangeSet(); } } @@ -276,22 +291,22 @@ public class Session extends SessionInvoker else if (m instanceof MessageTransfer) { MessageTransfer xfr = (MessageTransfer)m; - - if (xfr.getHeader() != null) + + Header header = xfr.getHeader(); + + if (header != null) { - if (xfr.getHeader().get(DeliveryProperties.class) != null) + if (header.getDeliveryProperties() != null) { - xfr.getHeader().get(DeliveryProperties.class).setRedelivered(true); + header.getDeliveryProperties().setRedelivered(true); } else { - Struct[] structs = xfr.getHeader().getStructs(); DeliveryProperties deliveryProps = new DeliveryProperties(); deliveryProps.setRedelivered(true); - - List<Struct> list = Arrays.asList(structs); - list.add(deliveryProps); - xfr.setHeader(new Header(list)); + + xfr.setHeader(new Header(deliveryProps, header.getMessageProperties(), + header.getNonStandardProperties())); } } @@ -299,7 +314,7 @@ public class Session extends SessionInvoker { DeliveryProperties deliveryProps = new DeliveryProperties(); deliveryProps.setRedelivered(true); - xfr.setHeader(new Header(deliveryProps)); + xfr.setHeader(new Header(deliveryProps, null, null)); } } sessionCommandPoint(m.getId(), 0); @@ -394,38 +409,46 @@ public class Session extends SessionInvoker public void processed(int command) { - processed(new Range(command, command)); + processed(command, command); } - public void processed(int lower, int upper) + public void processed(Range range) { - processed(new Range(lower, upper)); + processed(range.getLower(), range.getUpper()); } - public void processed(Range range) + public void processed(int lower, int upper) { - log.debug("%s processed(%s) %s %s", this, range, syncPoint, maxProcessed); + if(log.isDebugEnabled()) + { + log.debug("%s processed([%d,%d]) %s %s", this, lower, upper, syncPoint, maxProcessed); + } boolean flush; synchronized (processedLock) { - log.debug("%s", processed); + if(log.isDebugEnabled()) + { + log.debug("%s", processed); + } - if (ge(range.getUpper(), commandsIn)) + if (ge(upper, commandsIn)) { throw new IllegalArgumentException - ("range exceeds max received command-id: " + range); + ("range exceeds max received command-id: " + Range.newInstance(lower, upper)); } - processed.add(range); + processed.add(lower, upper); + Range first = processed.getFirst(); - int lower = first.getLower(); - int upper = first.getUpper(); + + int flower = first.getLower(); + int fupper = first.getUpper(); int old = maxProcessed; - if (le(lower, maxProcessed + 1)) + if (le(flower, maxProcessed + 1)) { - maxProcessed = max(maxProcessed, upper); + maxProcessed = max(maxProcessed, fupper); } boolean synced = ge(maxProcessed, syncPoint); flush = lt(old, syncPoint) && synced; @@ -442,7 +465,7 @@ public class Session extends SessionInvoker void flushExpected() { - RangeSet rs = new RangeSet(); + RangeSet rs = RangeSetFactory.createRangeSet(); synchronized (processedLock) { if (incomingInit) @@ -478,7 +501,7 @@ public class Session extends SessionInvoker { synchronized (processedLock) { - RangeSet newProcessed = new RangeSet(); + RangeSet newProcessed = RangeSetFactory.createRangeSet(); for (Range pr : processed) { for (Range kr : kc) @@ -534,7 +557,12 @@ public class Session extends SessionInvoker { maxComplete = max(maxComplete, upper); } - log.debug("%s commands remaining: %s", this, commandsOut - maxComplete); + + if(log.isDebugEnabled()) + { + log.debug("%s commands remaining: %s", this, commandsOut - maxComplete); + } + commands.notifyAll(); return gt(maxComplete, old); } @@ -801,8 +829,17 @@ public class Session extends SessionInvoker Waiter w = new Waiter(commands, timeout); while (w.hasTime() && state != CLOSED && lt(maxComplete, point)) { - checkFailoverRequired("Session sync was interrupted by failover."); - log.debug("%s waiting for[%d]: %d, %s", this, point, maxComplete, commands); + checkFailoverRequired("Session sync was interrupted by failover."); + if(log.isDebugEnabled()) + { + List<Method> waitingFor = + Arrays.asList(commands) + .subList(mod(maxComplete,commands.length), + mod(commandsOut-1, commands.length) < mod(maxComplete, commands.length) + ? commands.length-1 + : mod(commandsOut-1, commands.length)); + log.debug("%s waiting for[%d]: %d, %s", this, point, maxComplete, waitingFor); + } w.await(); } 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 3341149e5f..028b912ba1 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 @@ -91,21 +91,38 @@ public class SessionDelegate { RangeSet ranges = cmp.getCommands(); RangeSet known = null; - if (cmp.getTimelyReply()) - { - known = new RangeSet(); - } if (ranges != null) { - for (Range range : ranges) + if(ranges.size() == 1) { + Range range = ranges.getFirst(); boolean advanced = ssn.complete(range.getLower(), range.getUpper()); - if (advanced && known != null) + + if(advanced && cmp.getTimelyReply()) { - known.add(range); + known = range; } } + else + { + if (cmp.getTimelyReply()) + { + known = RangeSetFactory.createRangeSet(); + } + for (Range range : ranges) + { + boolean advanced = ssn.complete(range.getLower(), range.getUpper()); + if (advanced && known != null) + { + known.add(range); + } + } + } + } + else if (cmp.getTimelyReply()) + { + known = RangeSetFactory.createRangeSet(); } if (known != null) diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java index 09ce6a7eb1..6ff3b21400 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java @@ -29,12 +29,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; -import org.apache.qpid.transport.Binary; -import org.apache.qpid.transport.RangeSet; -import org.apache.qpid.transport.Struct; -import org.apache.qpid.transport.Type; - -import static org.apache.qpid.transport.util.Functions.*; +import org.apache.qpid.transport.*; /** @@ -194,18 +189,19 @@ abstract class AbstractDecoder implements Decoder public RangeSet readSequenceSet() { int count = readUint16()/8; - if (count == 0) + switch(count) { - return null; - } - else - { - RangeSet ranges = new RangeSet(); - for (int i = 0; i < count; i++) - { - ranges.add(readSequenceNo(), readSequenceNo()); - } - return ranges; + case 0: + return null; + case 1: + return Range.newInstance(readSequenceNo(), readSequenceNo()); + default: + RangeSet ranges = RangeSetFactory.createRangeSet(count); + for (int i = 0; i < count; i++) + { + ranges.add(readSequenceNo(), readSequenceNo()); + } + return ranges; } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java index 4486b03a67..d9150bed65 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java @@ -70,6 +70,16 @@ public final class BBEncoder extends AbstractEncoder return slice; } + public int position() + { + return out.position(); + } + + public ByteBuffer underlyingBuffer() + { + return out; + } + private void grow(int size) { ByteBuffer old = out; 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 1a85ab88a5..8cd5c29f6d 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 @@ -26,13 +26,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.qpid.transport.Header; -import org.apache.qpid.transport.Method; -import org.apache.qpid.transport.ProtocolError; -import org.apache.qpid.transport.ProtocolEvent; -import org.apache.qpid.transport.ProtocolHeader; -import org.apache.qpid.transport.Receiver; -import org.apache.qpid.transport.Struct; +import org.apache.qpid.transport.*; import org.apache.qpid.transport.codec.BBDecoder; /** @@ -198,12 +192,33 @@ public class Assembler implements Receiver<NetworkEvent>, NetworkDelegate break; case HEADER: command = getIncompleteCommand(channel); - List<Struct> structs = new ArrayList<Struct>(2); + List<Struct> structs = null; + DeliveryProperties deliveryProps = null; + MessageProperties messageProps = null; + while (dec.hasRemaining()) { - structs.add(dec.readStruct32()); + Struct struct = dec.readStruct32(); + if(struct instanceof DeliveryProperties && deliveryProps == null) + { + deliveryProps = (DeliveryProperties) struct; + } + else if(struct instanceof MessageProperties && messageProps == null) + { + messageProps = (MessageProperties) struct; + } + else + { + if(structs == null) + { + structs = new ArrayList<Struct>(2); + } + structs.add(struct); + } + } - command.setHeader(new Header(structs)); + command.setHeader(new Header(deliveryProps,messageProps,structs)); + if (frame.isLastSegment()) { setIncompleteCommand(channel, null); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java index 685034d1a9..6ac9df9bc3 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java @@ -87,27 +87,35 @@ public final class Disassembler implements Sender<ProtocolEvent>, ProtocolDelega } } + private final ByteBuffer _frameHeader = ByteBuffer.allocate(HEADER_SIZE); + + { + _frameHeader.order(ByteOrder.BIG_ENDIAN); + } + private void frame(byte flags, byte type, byte track, int channel, int size, ByteBuffer buf) { synchronized (sendlock) { - ByteBuffer data = ByteBuffer.allocate(size + HEADER_SIZE); - data.order(ByteOrder.BIG_ENDIAN); + ByteBuffer data = _frameHeader; + _frameHeader.rewind(); + data.put(0, flags); data.put(1, type); data.putShort(2, (short) (size + HEADER_SIZE)); data.put(5, track); data.putShort(6, (short) channel); - data.position(HEADER_SIZE); + int limit = buf.limit(); buf.limit(buf.position() + size); - data.put(buf); - buf.limit(limit); - + data.rewind(); sender.send(data); + sender.send(buf); + buf.limit(limit); + } } @@ -179,7 +187,7 @@ public final class Disassembler implements Sender<ProtocolEvent>, ProtocolDelega } } method.write(enc); - ByteBuffer methodSeg = enc.segment(); + int methodLimit = enc.position(); byte flags = FIRST_SEG; @@ -189,29 +197,44 @@ public final class Disassembler implements Sender<ProtocolEvent>, ProtocolDelega flags |= LAST_SEG; } - ByteBuffer headerSeg = null; + int headerLimit = -1; if (payload) { final Header hdr = method.getHeader(); if (hdr != null) { - final Struct[] structs = hdr.getStructs(); - - for (Struct st : structs) + if(hdr.getDeliveryProperties() != null) + { + enc.writeStruct32(hdr.getDeliveryProperties()); + } + if(hdr.getMessageProperties() != null) + { + enc.writeStruct32(hdr.getMessageProperties()); + } + if(hdr.getNonStandardProperties() != null) { - enc.writeStruct32(st); + for (Struct st : hdr.getNonStandardProperties()) + { + enc.writeStruct32(st); + } } } - headerSeg = enc.segment(); + headerLimit = enc.position(); } synchronized (sendlock) { - fragment(flags, type, method, methodSeg); + ByteBuffer buf = enc.underlyingBuffer(); + buf.position(0); + buf.limit(methodLimit); + + fragment(flags, type, method, buf); if (payload) { ByteBuffer body = method.getBody(); - fragment(body == null ? LAST_SEG : 0x0, SegmentType.HEADER, method, headerSeg); + buf.limit(headerLimit); + buf.position(methodLimit); + fragment(body == null ? LAST_SEG : 0x0, SegmentType.HEADER, method, buf); if (body != null) { fragment(LAST_SEG, SegmentType.BODY, method, body); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ByteBufferInputStream.java b/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java index 898a667736..b72b342187 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ByteBufferInputStream.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java @@ -18,12 +18,15 @@ * under the License. * */ -package org.apache.qpid.server.util; +package org.apache.qpid.util; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +/** + * Wraps @link {@link ByteBuffer} into {@link InputStream} + */ public class ByteBufferInputStream extends InputStream { private final ByteBuffer _buffer; @@ -36,13 +39,20 @@ public class ByteBufferInputStream extends InputStream @Override public int read() throws IOException { - return _buffer.get() & 0xFF; + if (_buffer.hasRemaining()) + { + return _buffer.get() & 0xFF; + } + return -1; } - @Override public int read(byte[] b, int off, int len) throws IOException { + if (!_buffer.hasRemaining()) + { + return -1; + } if(_buffer.remaining() < len) { len = _buffer.remaining(); @@ -73,9 +83,7 @@ public class ByteBufferInputStream extends InputStream @Override public long skip(long n) throws IOException { - _buffer.position(_buffer.position()+(int)n); - return n; } diff --git a/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java b/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java index bd189feb1c..cb9a9468bb 100644 --- a/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java +++ b/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java @@ -581,10 +581,10 @@ public class PropertyFieldTableTest extends TestCase table.setBytes("bytes", bytes); table.setChar("char", 'c'); - table.setDouble("double", Double.MAX_VALUE); - table.setFloat("float", Float.MAX_VALUE); table.setInteger("int", Integer.MAX_VALUE); table.setLong("long", Long.MAX_VALUE); + table.setDouble("double", Double.MAX_VALUE); + table.setFloat("float", Float.MAX_VALUE); table.setShort("short", Short.MAX_VALUE); table.setString("string", "hello"); table.setString("null-string", null); @@ -823,9 +823,7 @@ public class PropertyFieldTableTest extends TestCase */ public void testCheckPropertyNamehasMaxLength() { - String oldVal = System.getProperty("STRICT_AMQP"); - System.setProperty("STRICT_AMQP", "true"); - FieldTable table = new FieldTable(); + FieldTable table = new FieldTable(true); StringBuffer longPropertyName = new StringBuffer(129); @@ -845,14 +843,6 @@ public class PropertyFieldTableTest extends TestCase } // so length should be zero Assert.assertEquals(0, table.getEncodedSize()); - if (oldVal != null) - { - System.setProperty("STRICT_AMQP", oldVal); - } - else - { - System.clearProperty("STRICT_AMQP"); - } } /** @@ -860,9 +850,7 @@ public class PropertyFieldTableTest extends TestCase */ public void testCheckPropertyNameStartCharacterIsLetter() { - String oldVal = System.getProperty("STRICT_AMQP"); - System.setProperty("STRICT_AMQP", "true"); - FieldTable table = new FieldTable(); + FieldTable table = new FieldTable(true); // Try a name that starts with a number try @@ -876,14 +864,6 @@ public class PropertyFieldTableTest extends TestCase } // so length should be zero Assert.assertEquals(0, table.getEncodedSize()); - if (oldVal != null) - { - System.setProperty("STRICT_AMQP", oldVal); - } - else - { - System.clearProperty("STRICT_AMQP"); - } } /** @@ -891,9 +871,7 @@ public class PropertyFieldTableTest extends TestCase */ public void testCheckPropertyNameStartCharacterIsHashorDollar() { - String oldVal = System.getProperty("STRICT_AMQP"); - System.setProperty("STRICT_AMQP", "true"); - FieldTable table = new FieldTable(); + FieldTable table = new FieldTable(true); // Try a name that starts with a number try @@ -906,14 +884,6 @@ public class PropertyFieldTableTest extends TestCase fail("property name are allowed to start with # and $s"); } - if (oldVal != null) - { - System.setProperty("STRICT_AMQP", oldVal); - } - else - { - System.clearProperty("STRICT_AMQP"); - } } /** diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java index ad45d00e46..889250e004 100644 --- a/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java @@ -60,7 +60,7 @@ public class RangeSetTest extends TestCase public void test1() { - RangeSet ranges = new RangeSet(); + RangeSet ranges = RangeSetFactory.createRangeSet(); ranges.add(5, 10); check(ranges); ranges.add(15, 20); @@ -77,7 +77,7 @@ public class RangeSetTest extends TestCase public void test2() { - RangeSet rs = new RangeSet(); + RangeSet rs = RangeSetFactory.createRangeSet(); check(rs); rs.add(1); @@ -128,7 +128,7 @@ public class RangeSetTest extends TestCase public void testAddSelf() { - RangeSet a = new RangeSet(); + RangeSet a = RangeSetFactory.createRangeSet(); a.add(0, 8); check(a); a.add(0, 8); @@ -141,8 +141,8 @@ public class RangeSetTest extends TestCase public void testIntersect1() { - Range a = new Range(0, 10); - Range b = new Range(9, 20); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(9, 20); Range i1 = a.intersect(b); Range i2 = b.intersect(a); assertEquals(i1.getUpper(), 10); @@ -153,16 +153,16 @@ public class RangeSetTest extends TestCase public void testIntersect2() { - Range a = new Range(0, 10); - Range b = new Range(11, 20); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(11, 20); assertNull(a.intersect(b)); assertNull(b.intersect(a)); } public void testIntersect3() { - Range a = new Range(0, 10); - Range b = new Range(3, 5); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(3, 5); Range i1 = a.intersect(b); Range i2 = b.intersect(a); assertEquals(i1.getUpper(), 5); @@ -173,14 +173,14 @@ public class RangeSetTest extends TestCase public void testSubtract1() { - Range a = new Range(0, 10); + Range a = Range.newInstance(0, 10); assertTrue(a.subtract(a).isEmpty()); } public void testSubtract2() { - Range a = new Range(0, 10); - Range b = new Range(20, 30); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(20, 30); List<Range> ranges = a.subtract(b); assertEquals(ranges.size(), 1); Range d = ranges.get(0); @@ -190,8 +190,8 @@ public class RangeSetTest extends TestCase public void testSubtract3() { - Range a = new Range(20, 30); - Range b = new Range(0, 10); + Range a = Range.newInstance(20, 30); + Range b = Range.newInstance(0, 10); List<Range> ranges = a.subtract(b); assertEquals(ranges.size(), 1); Range d = ranges.get(0); @@ -201,8 +201,8 @@ public class RangeSetTest extends TestCase public void testSubtract4() { - Range a = new Range(0, 10); - Range b = new Range(3, 5); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(3, 5); List<Range> ranges = a.subtract(b); assertEquals(ranges.size(), 2); Range low = ranges.get(0); @@ -215,8 +215,8 @@ public class RangeSetTest extends TestCase public void testSubtract5() { - Range a = new Range(0, 10); - Range b = new Range(3, 20); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(3, 20); List<Range> ranges = a.subtract(b); assertEquals(ranges.size(), 1); Range d = ranges.get(0); @@ -226,8 +226,8 @@ public class RangeSetTest extends TestCase public void testSubtract6() { - Range a = new Range(0, 10); - Range b = new Range(-10, 5); + Range a = Range.newInstance(0, 10); + Range b = Range.newInstance(-10, 5); List<Range> ranges = a.subtract(b); assertEquals(ranges.size(), 1); Range d = ranges.get(0); diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/ByteBufferInputStreamTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/ByteBufferInputStreamTest.java new file mode 100644 index 0000000000..0b393a489f --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/util/ByteBufferInputStreamTest.java @@ -0,0 +1,111 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.util; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import junit.framework.TestCase; + +public class ByteBufferInputStreamTest extends TestCase +{ + private byte[] _data = {2, 1, 5, 3, 4}; + private ByteBufferInputStream _inputStream; + + public void setUp() throws Exception + { + _inputStream = new ByteBufferInputStream(ByteBuffer.wrap(_data)); + } + + public void testRead() throws IOException + { + for (int i = 0; i < _data.length; i++) + { + assertEquals("Unexpected byte at position " + i, _data[i], _inputStream.read()); + } + assertEquals("EOF not reached", -1, _inputStream.read()); + } + + public void testReadByteArray() throws IOException + { + byte[] readBytes = new byte[_data.length]; + int length = _inputStream.read(readBytes, 0, 2); + + byte[] expected = new byte[_data.length]; + System.arraycopy(_data, 0, expected, 0, 2); + + assertTrue("Unexpected data", Arrays.equals(expected, readBytes)); + assertEquals("Unexpected length", 2, length); + + length = _inputStream.read(readBytes, 2, 3); + + assertTrue("Unexpected data", Arrays.equals(_data, readBytes)); + assertEquals("Unexpected length", 3, length); + + length = _inputStream.read(readBytes); + assertEquals("EOF not reached", -1, length); + } + + public void testSkip() throws IOException + { + _inputStream.skip(3); + byte[] readBytes = new byte[_data.length - 3]; + int length = _inputStream.read(readBytes); + + byte[] expected = new byte[_data.length - 3]; + System.arraycopy(_data, 3, expected, 0, _data.length - 3); + + assertTrue("Unexpected data", Arrays.equals(expected, readBytes)); + assertEquals("Unexpected length", _data.length - 3, length); + } + + public void testAvailable() throws IOException + { + int available = _inputStream.available(); + assertEquals("Unexpected number of available bytes", _data.length, available); + byte[] readBytes = new byte[_data.length]; + _inputStream.read(readBytes); + available = _inputStream.available(); + assertEquals("Unexpected number of available bytes", 0, available); + } + + public void testMarkReset() throws IOException + { + _inputStream.mark(0); + byte[] readBytes = new byte[_data.length]; + int length = _inputStream.read(readBytes); + assertEquals("Unexpected length", _data.length, length); + assertEquals("Unexpected number of available bytes", 0, _inputStream.available()); + + _inputStream.reset(); + readBytes = new byte[_data.length]; + length = _inputStream.read(readBytes); + assertEquals("Unexpected length", _data.length, length); + assertEquals("Unexpected number of available bytes", 0, _inputStream.available()); + } + + public void testMarkSupported() throws IOException + { + assertTrue("Unexpected mark supported", _inputStream.markSupported()); + } + +} diff --git a/qpid/java/common/templates/method/version/MethodBodyClass.vm b/qpid/java/common/templates/method/version/MethodBodyClass.vm index ce8a453eeb..0e444b87df 100644 --- a/qpid/java/common/templates/method/version/MethodBodyClass.vm +++ b/qpid/java/common/templates/method/version/MethodBodyClass.vm @@ -46,8 +46,9 @@ package org.apache.qpid.framing.amqp_$version.getMajor()_$version.getMinor(); -import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataInput; +import org.apache.qpid.codec.MarkableDataInput; +import java.io.DataOutput; import java.io.IOException; import java.util.HashMap; @@ -58,7 +59,7 @@ public class ${javaClassName} extends AMQMethodBody_$version.getMajor()_$version { private static final AMQMethodBodyInstanceFactory FACTORY_INSTANCE = new AMQMethodBodyInstanceFactory() { - public AMQMethodBody newInstance(DataInputStream in, long size) throws AMQFrameDecodingException, IOException + public AMQMethodBody newInstance(MarkableDataInput in, long size) throws AMQFrameDecodingException, IOException { return new ${javaClassName}(in); } @@ -86,7 +87,7 @@ public class ${javaClassName} extends AMQMethodBody_$version.getMajor()_$version // Constructor - public ${javaClassName}(DataInputStream buffer) throws AMQFrameDecodingException, IOException + public ${javaClassName}(MarkableDataInput buffer) throws AMQFrameDecodingException, IOException { #foreach( $field in $method.ConsolidatedFields ) _$field.Name = read$field.getEncodingType()( buffer ); @@ -171,7 +172,7 @@ public class ${javaClassName} extends AMQMethodBody_$version.getMajor()_$version return size; } - public void writeMethodPayload(DataOutputStream buffer) throws IOException + public void writeMethodPayload(DataOutput buffer) throws IOException { #foreach( $field in $method.ConsolidatedFields ) write$field.getEncodingType()( buffer, _$field.Name ); diff --git a/qpid/java/common/templates/model/MethodRegistryClass.vm b/qpid/java/common/templates/model/MethodRegistryClass.vm index 8258175ce7..f8a55f245a 100644 --- a/qpid/java/common/templates/model/MethodRegistryClass.vm +++ b/qpid/java/common/templates/model/MethodRegistryClass.vm @@ -30,10 +30,10 @@ package org.apache.qpid.framing; -import java.io.DataInputStream; import java.io.IOException; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.codec.MarkableDataInput; import java.util.Map; import java.util.HashMap; @@ -54,7 +54,7 @@ public abstract class MethodRegistry #end - public abstract AMQMethodBody convertToBody(DataInputStream in, long size) + public abstract AMQMethodBody convertToBody(MarkableDataInput in, long size) throws AMQFrameDecodingException, IOException; public abstract int getMaxClassId(); diff --git a/qpid/java/common/templates/model/version/MethodRegistryClass.vm b/qpid/java/common/templates/model/version/MethodRegistryClass.vm index 79553f7748..ab5db0ea38 100644 --- a/qpid/java/common/templates/model/version/MethodRegistryClass.vm +++ b/qpid/java/common/templates/model/version/MethodRegistryClass.vm @@ -35,10 +35,10 @@ import org.apache.qpid.protocol.AMQConstant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.DataInputStream; import java.io.IOException; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; +import org.apache.qpid.codec.MarkableDataInput; public class MethodRegistry_$version.getMajor()_$version.getMinor() extends MethodRegistry @@ -87,7 +87,7 @@ public class MethodRegistry_$version.getMajor()_$version.getMinor() extends Meth } - public AMQMethodBody convertToBody(DataInputStream in, long size) + public AMQMethodBody convertToBody(MarkableDataInput in, long size) throws AMQFrameDecodingException, IOException { int classId = in.readUnsignedShort(); diff --git a/qpid/java/jca/example/qpid-jca-example-properties.xml b/qpid/java/jca/example/qpid-jca-example-properties.xml index ee0478a6e5..076e5dc241 100644 --- a/qpid/java/jca/example/qpid-jca-example-properties.xml +++ b/qpid/java/jca/example/qpid-jca-example-properties.xml @@ -49,17 +49,17 @@ value="responder.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/> <property name="qpid.hello.topic.dest.address.BURL" - value="topic://amq.topic//hello.jcaTopic?routingKey='hello.jcaTopic',autodelete='true'"/> + value="BURL:topic://amq.topic//hello.jcaTopic?routingKey='hello.jcaTopic',autodelete='true'"/> <property name="qpid.goodbye.topic.dest.address.BURL" - value="topic://amq.topic//goodbye.jcaTopic?routingKey='goodbye.jcaTopic',autodelete='true'"/> + value="BURL:topic://amq.topic//goodbye.jcaTopic?routingKey='goodbye.jcaTopic',autodelete='true'"/> <property name="qpid.hellogoodbye.topic.dest.address.BURL" - value="topic://amq.topic//#.jcaTopic"/> + value="BURL:topic://amq.topic//#.jcaTopic"/> <property name="qpid.hello.queue.dest.address.BURL" - value="direct://amq.direct//hello.Queue?routingkey='hello.Queue'"/> + value="BURL:direct://amq.direct//hello.Queue?routingkey='hello.Queue'"/> <property name="qpid.goodbye.queue.dest.address.BURL" - value="direct://amq.direct//goodbye.Queue?routingkey='goodbye.Queue'"/> + value="BURL:direct://amq.direct//goodbye.Queue?routingkey='goodbye.Queue'"/> <property name="qpid.responder.queue.dest.address.BURL" - value="direct://amq.direct//responder.Queue?routingkey='responder.Queue'"/> + value="BURL:direct://amq.direct//responder.Queue?routingkey='responder.Queue'"/> <!-- This macro allows us to construct a property name which contains a property expansion --> <macrodef name="set-address-property"> diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java index fb1b7f060c..53896d8872 100644 --- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java +++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java @@ -57,6 +57,8 @@ import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.xa.XAResource; +import org.apache.qpid.client.Closeable; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -752,26 +754,25 @@ public class QpidRAManagedConnection implements ManagedConnection, ExceptionList try { - boolean transacted = _cri.isTransacted(); - int acknowledgeMode = Session.AUTO_ACKNOWLEDGE; - boolean localTx = _mcf.getUseLocalTx(); + boolean transacted = _cri.isTransacted() || _mcf.getUseLocalTx(); + int acknowledgeMode = (transacted) ? Session.SESSION_TRANSACTED : _cri.getAcknowledgeMode(); if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION) { if (_userName != null && _password != null) { - if(!localTx) + if(!transacted) { _connection = _mcf.getCleanAMQConnectionFactory().createXATopicConnection(_userName, _password); } else { - _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection(); + _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection(_userName, _password); } } else { - if(!localTx) + if(!transacted) { _connection = _mcf.getDefaultAMQConnectionFactory().createXATopicConnection(); } @@ -781,32 +782,31 @@ public class QpidRAManagedConnection implements ManagedConnection, ExceptionList } } - if(!localTx) + if(!transacted) { _xaSession = ((XATopicConnection)_connection).createXATopicSession(); - } else { - _session = ((TopicConnection)_connection).createTopicSession(localTx, acknowledgeMode); + _session = ((TopicConnection)_connection).createTopicSession(transacted, acknowledgeMode); } } else if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION) { if (_userName != null && _password != null) { - if(!localTx) + if(!transacted) { _connection = _mcf.getCleanAMQConnectionFactory().createXAQueueConnection(_userName, _password); } else { - _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection(); + _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection(_userName, _password); } } else { - if(!localTx) + if(!transacted) { _connection = _mcf.getDefaultAMQConnectionFactory().createXAQueueConnection(); } @@ -816,14 +816,14 @@ public class QpidRAManagedConnection implements ManagedConnection, ExceptionList } } - if(!localTx) + if(!transacted) { _xaSession = ((XAQueueConnection)_connection).createXAQueueSession(); } else { - _session = ((QueueConnection)_connection).createQueueSession(localTx, acknowledgeMode); + _session = ((QueueConnection)_connection).createQueueSession(transacted, acknowledgeMode); } } @@ -831,18 +831,18 @@ public class QpidRAManagedConnection implements ManagedConnection, ExceptionList { if (_userName != null && _password != null) { - if(!localTx) + if(!transacted) { _connection = _mcf.getCleanAMQConnectionFactory().createXAConnection(_userName, _password); } else { - _connection = _mcf.getCleanAMQConnectionFactory().createConnection(); + _connection = _mcf.getCleanAMQConnectionFactory().createConnection(_userName, _password); } } else { - if(!localTx) + if(!transacted) { _connection = _mcf.getDefaultAMQConnectionFactory().createXAConnection(); } @@ -852,22 +852,24 @@ public class QpidRAManagedConnection implements ManagedConnection, ExceptionList } } - if(!localTx) + if(!transacted) { _xaSession = ((XAQueueConnection)_connection).createXASession(); } else { - _session = ((QueueConnection)_connection).createSession(localTx, acknowledgeMode); + _session = ((QueueConnection)_connection).createSession(transacted, acknowledgeMode); } } _connection.setExceptionListener(this); + } catch (JMSException je) { + _log.error(je.getMessage(), je); throw new ResourceException(je.getMessage(), je); } } @@ -877,4 +879,9 @@ public class QpidRAManagedConnection implements ManagedConnection, ExceptionList this._inManagedTx = inManagedTx; } + public boolean isConnectionClosed() + { + Closeable c = (Closeable)_connection; + return (c == null || c.isClosed() || c.isClosing()); + } } diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java index 691fe8c40a..295a453010 100644 --- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java +++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java @@ -71,7 +71,7 @@ public class QpidRAMessage implements Message _log.trace("acknowledge()"); } - _session.getSession(); // Check for closed + _session.getSessionInternal(); // Check for closed _message.acknowledge(); } diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java index a270253c13..fdd4888a3d 100644 --- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java +++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java @@ -410,19 +410,24 @@ public class QpidRASessionImpl implements Session, QueueSession, TopicSession, X lock(); try { - Session session = getSessionInternal(); if (_cri.isTransacted() == false) { throw new IllegalStateException("Session is not transacted"); } + if(_lockedMC.isConnectionClosed()) + { + throw new IllegalStateException("Attempting to call commit when the underlying connection has been closed."); + } + if (_log.isTraceEnabled()) { _log.trace("Commit session " + this); } - session.commit(); + getSessionInternal().commit(); + } finally { diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java index 98427d7f9d..57edec8eee 100644 --- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java +++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java @@ -113,6 +113,9 @@ public class QpidActivation implements ExceptionListener // Whether we are in the failure recovery loop private AtomicBoolean _inFailure = new AtomicBoolean(false); + //Whether or not we have completed activating + private AtomicBoolean _activated = new AtomicBoolean(false); + static { try @@ -242,7 +245,7 @@ public class QpidActivation implements ExceptionListener _log.trace("start()"); } _deliveryActive.set(true); - _ra.getWorkManager().scheduleWork(new SetupActivation()); + new Thread(new SetupActivation()).start(); } /** @@ -323,8 +326,10 @@ public class QpidActivation implements ExceptionListener throw e; } } + amqConnection.start() ; this._connection = amqConnection ; + _activated.set(true); _log.debug("Setup complete " + this); } @@ -422,7 +427,6 @@ public class QpidActivation implements ExceptionListener " of type " + destinationType.getName()); _destination = Util.lookup(ctx, destinationName, destinationType); - //_destination = (Destination)ctx.lookup(destinationName); } else @@ -490,7 +494,14 @@ public class QpidActivation implements ExceptionListener public void onException(final JMSException jmse) { - handleFailure(jmse) ; + if(_activated.get()) + { + handleFailure(jmse) ; + } + else + { + _log.warn("Received JMSException: " + jmse + " while endpoint was not activated."); + } } /** diff --git a/qpid/java/lib/cobertura/README.txt b/qpid/java/lib/cobertura/README.txt index 8e4cc09a80..080bb5f2f3 100644 --- a/qpid/java/lib/cobertura/README.txt +++ b/qpid/java/lib/cobertura/README.txt @@ -1,10 +1,9 @@ -Download the cobertura binary from the following location:
+Download the cobertura binary from the following location and expand it into +this directory. http://cobertura.sourceforge.net/download.html -
-Unpack it into the cobertura (this) directory with tar --strip-path 1 -xf. -This should leave you with cobertura.jar in qpid/java/lib/cobertura.
+Alternatively run "ant download-cobertura" to do this automatically. +(to set a http proxy for ant use ANT_OPTS="-Dhttp.proxyHost=<host> -Dhttp.proxyPort=<port>") Run "ant cover-test coverage-report" to generate coverage report. - diff --git a/qpid/java/lib/poms/je-4.0.117.xml b/qpid/java/lib/poms/je-4.0.117.xml deleted file mode 100644 index 85573a99f9..0000000000 --- a/qpid/java/lib/poms/je-4.0.117.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0"?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<dep> - <groupId>com.sleepycat</groupId> - <artifactId>je</artifactId> - <version>4.0.117</version> -</dep> diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java index d2950b095b..5c5ad66777 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java @@ -5,12 +5,14 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import javax.jms.Connection; +import javax.jms.Destination; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; +import javax.jms.TextMessage; import org.apache.qpid.configuration.ClientProperties; import org.apache.qpid.test.utils.QpidBrokerTestCase; @@ -133,4 +135,41 @@ public class PrefetchBehaviourTest extends QpidBrokerTestCase assertFalse("Unexpecte exception during async message processing",_exceptionCaught.get()); } + /** + * Test Goal: Verify if connection stop releases all messages in it's prefetch buffer. + * Test Strategy: Send 10 messages to a queue. Create a consumer with maxprefetch of 5, but never consume them. + * Stop the connection. Create a new connection and a consumer with maxprefetch 10 on the same queue. + * Try to receive all 10 messages. + */ + public void testConnectionStop() throws Exception + { + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "10"); + Connection con = getConnection(); + con.start(); + Session ssn = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination queue = ssn.createQueue("ADDR:my-queue;{create: always}"); + + MessageProducer prod = ssn.createProducer(queue); + for (int i=0; i<10;i++) + { + prod.send(ssn.createTextMessage("Msg" + i)); + } + + MessageConsumer consumer = ssn.createConsumer(queue); + // This is to ensure we get the first client to prefetch. + Message msg = consumer.receive(1000); + assertNotNull("The first consumer should get one message",msg); + con.stop(); + + Connection con2 = getConnection(); + con2.start(); + Session ssn2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer2 = ssn2.createConsumer(queue); + for (int i=0; i<9;i++) + { + TextMessage m = (TextMessage)consumer2.receive(1000); + assertNotNull("The second consumer should get 9 messages, but received only " + i,m); + } + } + } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java new file mode 100644 index 0000000000..08a932eba1 --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java @@ -0,0 +1,481 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, 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.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.HashMap; +import java.util.Map; + +public class MessageGroupQueueTest extends QpidBrokerTestCase +{ + protected final String QUEUE = "MessageGroupQueue"; + + private Connection producerConnection; + private MessageProducer producer; + private Session producerSession; + private Queue queue; + private Connection consumerConnection; + + + protected void setUp() throws Exception + { + super.setUp(); + + producerConnection = getConnection(); + producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + producerConnection.start(); + + consumerConnection = getConnection(); + + } + + protected void tearDown() throws Exception + { + producerConnection.close(); + consumerConnection.close(); + super.tearDown(); + } + + + public void testSimpleGroupAssignment() throws Exception + { + simpleGroupAssignment(false); + } + + public void testSharedGroupSimpleGroupAssignment() throws Exception + { + simpleGroupAssignment(true); + } + + + /** + * Pre populate the queue with messages with groups as follows + * + * ONE + * TWO + * ONE + * TWO + * + * Create two consumers with prefetch of 1, the first consumer should then be assigned group ONE, the second + * consumer assigned group TWO if they are started in sequence. + * + * Thus doing + * + * c1 <--- (ONE) + * c2 <--- (TWO) + * c2 ack ---> + * + * c2 should now be able to receive a second message from group TWO (skipping over the message from group ONE) + * + * i.e. + * + * c2 <--- (TWO) + * c2 ack ---> + * c1 <--- (ONE) + * c1 ack ---> + * + */ + private void simpleGroupAssignment(boolean sharedGroups) throws AMQException, JMSException + { + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.group_header_key","group"); + if(sharedGroups) + { + arguments.put("qpid.shared_msg_group","1"); + } + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + String[] groups = { "ONE", "TWO"}; + + for (int msg = 0; msg < 4; msg++) + { + producer.send(createMessage(msg, groups[msg % groups.length])); + } + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1); + + + MessageConsumer consumer1 = cs1.createConsumer(queue); + MessageConsumer consumer2 = cs2.createConsumer(queue); + + consumerConnection.start(); + Message cs1Received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received first message", cs1Received); + + Message cs2Received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received first message", cs2Received); + + cs1Received.acknowledge(); + cs2Received.acknowledge(); + + Message cs2Received2 = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received second message", cs2Received2); + assertEquals("Differing groups", cs2Received2.getStringProperty("group"), + cs2Received.getStringProperty("group")); + + Message cs1Received2 = consumer1.receive(1000); + + assertNotNull("Consumer 1 should have received second message", cs1Received2); + assertEquals("Differing groups", cs1Received2.getStringProperty("group"), + cs1Received.getStringProperty("group")); + + cs1Received2.acknowledge(); + cs2Received2.acknowledge(); + + assertNull(consumer1.receive(1000)); + assertNull(consumer2.receive(1000)); + } + + + public void testConsumerCloseGroupAssignment() throws Exception + { + consumerCloseGroupAssignment(false); + } + + public void testSharedGroupConsumerCloseGroupAssignment() throws Exception + { + consumerCloseGroupAssignment(true); + } + + /** + * + * Tests that upon closing a consumer, groups previously assigned to that consumer are reassigned to a different + * consumer. + * + * Pre-populate the queue as ONE, ONE, TWO, ONE + * + * create in sequence two consumers + * + * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2) + * + * Then close c1 before acking. + * + * If we now attempt to receive from c2, then the remaining messages in group ONE should be available (which + * requires c2 to go "backwards" in the queue). + * + **/ + private void consumerCloseGroupAssignment(boolean sharedGroups) throws AMQException, JMSException + { + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.group_header_key","group"); + if(sharedGroups) + { + arguments.put("qpid.shared_msg_group","1"); + } + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + producer.send(createMessage(1, "ONE")); + producer.send(createMessage(2, "ONE")); + producer.send(createMessage(3, "TWO")); + producer.send(createMessage(4, "ONE")); + + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + + MessageConsumer consumer1 = cs1.createConsumer(queue); + + consumerConnection.start(); + MessageConsumer consumer2 = cs2.createConsumer(queue); + + Message cs1Received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received first message", cs1Received); + assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg")); + + Message cs2Received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received first message", cs2Received); + assertEquals("incorrect message received", 3, cs2Received.getIntProperty("msg")); + cs2.commit(); + + Message cs2Received2 = consumer2.receive(1000); + + assertNull("Consumer 2 should not yet have received a second message", cs2Received2); + + consumer1.close(); + + cs1.commit(); + Message cs2Received3 = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received second message", cs2Received3); + assertEquals("Unexpected group", "ONE", cs2Received3.getStringProperty("group")); + assertEquals("incorrect message received", 2, cs2Received3.getIntProperty("msg")); + + cs2.commit(); + + + Message cs2Received4 = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received third message", cs2Received4); + assertEquals("Unexpected group", "ONE", cs2Received4.getStringProperty("group")); + assertEquals("incorrect message received", 4, cs2Received4.getIntProperty("msg")); + cs2.commit(); + + assertNull(consumer2.receive(1000)); + } + + + + + public void testConsumerCloseWithRelease() throws Exception + { + consumerCloseWithRelease(false); + } + + public void testSharedGroupConsumerCloseWithRelease() throws Exception + { + consumerCloseWithRelease(true); + } + + + /** + * + * Tests that upon closing a consumer and its session, groups previously assigned to that consumer are reassigned + * toa different consumer, including messages which were previously delivered but have now been released. + * + * Pre-populate the queue as ONE, ONE, TWO, ONE + * + * create in sequence two consumers + * + * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2) + * + * Then close c1 and its session without acking. + * + * If we now attempt to receive from c2, then the all messages in group ONE should be available (which + * requires c2 to go "backwards" in the queue). The first such message should be marked as redelivered + * + */ + private void consumerCloseWithRelease(boolean sharedGroups) throws AMQException, JMSException + { + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.group_header_key","group"); + if(sharedGroups) + { + arguments.put("qpid.shared_msg_group","1"); + } + + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + producer.send(createMessage(1, "ONE")); + producer.send(createMessage(2, "ONE")); + producer.send(createMessage(3, "TWO")); + producer.send(createMessage(4, "ONE")); + + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + + + MessageConsumer consumer1 = cs1.createConsumer(queue); + + consumerConnection.start(); + + MessageConsumer consumer2 = cs2.createConsumer(queue); + + Message cs1Received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its first message", cs1Received); + assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg")); + + Message received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received its first message", received); + assertEquals("incorrect message received", 3, received.getIntProperty("msg")); + + received = consumer2.receive(1000); + + assertNull("Consumer 2 should not yet have received second message", received); + + consumer1.close(); + cs1.close(); + cs2.commit(); + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should now have received second message", received); + assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); + assertEquals("incorrect message received", 1, received.getIntProperty("msg")); + assertTrue("Expected second message to be marked as redelivered " + received.getIntProperty("msg"), + received.getJMSRedelivered()); + + cs2.commit(); + + + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received a third message", received); + assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); + assertEquals("incorrect message received", 2, received.getIntProperty("msg")); + + cs2.commit(); + + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received a fourth message", received); + assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); + assertEquals("incorrect message received", 4, received.getIntProperty("msg")); + + cs2.commit(); + + + assertNull(consumer2.receive(1000)); + } + + public void testGroupAssignmentSurvivesEmpty() throws JMSException, AMQException + { + groupAssignmentOnEmpty(false); + } + + public void testSharedGroupAssignmentDoesNotSurviveEmpty() throws JMSException, AMQException + { + groupAssignmentOnEmpty(true); + } + + private void groupAssignmentOnEmpty(boolean sharedGroups) throws AMQException, JMSException + { + final Map<String,Object> arguments = new HashMap<String, Object>(); + arguments.put("qpid.group_header_key","group"); + if(sharedGroups) + { + arguments.put("qpid.shared_msg_group","1"); + } + + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + producer.send(createMessage(1, "ONE")); + producer.send(createMessage(2, "TWO")); + producer.send(createMessage(3, "THREE")); + producer.send(createMessage(4, "ONE")); + + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + + + MessageConsumer consumer1 = cs1.createConsumer(queue); + + consumerConnection.start(); + + MessageConsumer consumer2 = cs2.createConsumer(queue); + + Message received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its first message", received); + assertEquals("incorrect message received", 1, received.getIntProperty("msg")); + + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received its first message", received); + assertEquals("incorrect message received", 2, received.getIntProperty("msg")); + + cs1.commit(); + + received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its second message", received); + assertEquals("incorrect message received", 3, received.getIntProperty("msg")); + + // We expect different behaviours from "shared groups": here the assignment of a subscription to a group + // is terminated when there are no outstanding delivered but unacknowledged messages. In contrast, with a + // standard message grouping queue the assignment will be retained until the subscription is no longer + // registered + if(sharedGroups) + { + cs2.commit(); + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received its second message", received); + assertEquals("incorrect message received", 4, received.getIntProperty("msg")); + + cs2.commit(); + } + else + { + cs2.commit(); + received = consumer2.receive(1000); + + assertNull("Consumer 2 should not have received a second message", received); + + cs1.commit(); + + received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its third message", received); + assertEquals("incorrect message received", 4, received.getIntProperty("msg")); + + } + + } + + + private Message createMessage(int msg, String group) throws JMSException + { + Message send = producerSession.createTextMessage("Message: " + msg); + send.setIntProperty("msg", msg); + send.setStringProperty("group", group); + + return send; + } +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java index 775d2c3eb0..47f334adf6 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java @@ -154,8 +154,7 @@ public class ProducerFlowControlTest extends AbstractTestLogging // try to send 5 messages (should block after 4) sendMessagesAsync(producer, producerSession, 5, 50L); - Thread.sleep(5000); - List<String> results = waitAndFindMatches("QUE-1003"); + List<String> results = waitAndFindMatches("QUE-1003", 7000); assertEquals("Did not find correct number of QUE-1003 queue overfull messages", 1, results.size()); @@ -199,11 +198,13 @@ public class ProducerFlowControlTest extends AbstractTestLogging // try to send 5 messages (should block after 4) MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L); - Thread.sleep(TIMEOUT); List<String> results = waitAndFindMatches("Message send delayed by", TIMEOUT); assertTrue("No delay messages logged by client",results.size()!=0); - results = findMatches("Message send failed due to timeout waiting on broker enforced flow control"); - assertEquals("Incorrect number of send failure messages logged by client",1,results.size()); + + List<String> failedMessages = waitAndFindMatches("Message send failed due to timeout waiting on broker enforced" + + " flow control", TIMEOUT); + assertEquals("Incorrect number of send failure messages logged by client (got " + results.size() + " delay " + + "messages)",1,failedMessages.size()); @@ -325,8 +326,9 @@ public class ProducerFlowControlTest extends AbstractTestLogging // try to send 5 messages (should block after 4) - MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L); + MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 100L); + Thread.sleep(10000); Exception e = sender.getException(); @@ -440,6 +442,15 @@ public class ProducerFlowControlTest extends AbstractTestLogging e.printStackTrace(); throw new RuntimeException(e); } + + try + { + Thread.sleep(sleepPeriod); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } } } 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 a5c38e7e33..2d450cf09c 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 @@ -22,11 +22,13 @@ 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.AMQStoreException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.federation.Bridge; +import org.apache.qpid.server.federation.BrokerLink; +import org.apache.qpid.server.message.EnqueableMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.logging.LogSubject; @@ -35,7 +37,7 @@ import java.util.HashMap; import java.util.Iterator; import java.nio.ByteBuffer; -public class SlowMessageStore implements MessageStore +public class SlowMessageStore implements MessageStore, DurableConfigurationStore { private static final Logger _logger = Logger.getLogger(SlowMessageStore.class); private static final String DELAYS = "delays"; @@ -43,6 +45,7 @@ public class SlowMessageStore implements MessageStore private HashMap<String, Long> _postDelays = new HashMap<String, Long>(); private long _defaultDelay = 0L; private MessageStore _realStore = new MemoryMessageStore(); + private DurableConfigurationStore _durableConfigurationStore = (MemoryMessageStore) _realStore; private static final String PRE = "pre"; private static final String POST = "post"; private String DEFAULT_DELAY = "default"; @@ -80,12 +83,13 @@ public class SlowMessageStore implements MessageStore " does not."); } _realStore = (MessageStore) o; - _realStore.configureConfigStore(name, recoveryHandler, config, logSubject); - } - else - { - _realStore.configureConfigStore(name, recoveryHandler, config, logSubject); + if(o instanceof DurableConfigurationStore) + { + _durableConfigurationStore = (DurableConfigurationStore)o; + } } + _durableConfigurationStore.configureConfigStore(name, recoveryHandler, config, logSubject); + } private void configureDelays(Configuration config) @@ -178,28 +182,28 @@ public class SlowMessageStore implements MessageStore public void createExchange(Exchange exchange) throws AMQStoreException { doPreDelay("createExchange"); - _realStore.createExchange(exchange); + _durableConfigurationStore.createExchange(exchange); doPostDelay("createExchange"); } public void removeExchange(Exchange exchange) throws AMQStoreException { doPreDelay("removeExchange"); - _realStore.removeExchange(exchange); + _durableConfigurationStore.removeExchange(exchange); doPostDelay("removeExchange"); } public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { doPreDelay("bindQueue"); - _realStore.bindQueue(exchange, routingKey, queue, args); + _durableConfigurationStore.bindQueue(exchange, routingKey, queue, args); doPostDelay("bindQueue"); } public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException { doPreDelay("unbindQueue"); - _realStore.unbindQueue(exchange, routingKey, queue, args); + _durableConfigurationStore.unbindQueue(exchange, routingKey, queue, args); doPostDelay("unbindQueue"); } @@ -211,14 +215,14 @@ public class SlowMessageStore implements MessageStore public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQStoreException { doPreDelay("createQueue"); - _realStore.createQueue(queue, arguments); + _durableConfigurationStore.createQueue(queue, arguments); doPostDelay("createQueue"); } public void removeQueue(AMQQueue queue) throws AMQStoreException { doPreDelay("removeQueue"); - _realStore.removeQueue(queue); + _durableConfigurationStore.removeQueue(queue); doPostDelay("removeQueue"); } @@ -268,19 +272,19 @@ public class SlowMessageStore implements MessageStore _underlying = underlying; } - public void enqueueMessage(TransactionLogResource queue, Long messageId) + public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { doPreDelay("enqueueMessage"); - _underlying.enqueueMessage(queue, messageId); + _underlying.enqueueMessage(queue, message); doPostDelay("enqueueMessage"); } - public void dequeueMessage(TransactionLogResource queue, Long messageId) + public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException { doPreDelay("dequeueMessage"); - _underlying.dequeueMessage(queue, messageId); + _underlying.dequeueMessage(queue, message); doPostDelay("dequeueMessage"); } @@ -313,9 +317,36 @@ public class SlowMessageStore implements MessageStore public void updateQueue(AMQQueue queue) throws AMQStoreException { doPreDelay("updateQueue"); - _realStore.updateQueue(queue); + _durableConfigurationStore.updateQueue(queue); doPostDelay("updateQueue"); } + public void createBrokerLink(final BrokerLink link) throws AMQStoreException + { + doPreDelay("createBrokerLink"); + _durableConfigurationStore.createBrokerLink(link); + doPostDelay("createBrokerLink"); + } + + public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException + { + doPreDelay("deleteBrokerLink"); + _durableConfigurationStore.deleteBrokerLink(link); + doPostDelay("deleteBrokerLink"); + } + + public void createBridge(final Bridge bridge) throws AMQStoreException + { + doPreDelay("createBridge"); + _durableConfigurationStore.createBridge(bridge); + doPostDelay("createBridge"); + } + + public void deleteBridge(final Bridge bridge) throws AMQStoreException + { + doPreDelay("deleteBridge"); + _durableConfigurationStore.deleteBridge(bridge); + doPostDelay("deleteBridge"); + } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java index 147a03be0c..fa16152b69 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java @@ -138,4 +138,21 @@ public class ObjectMessageTest extends QpidBrokerTestCase assertEquals("Second read: UUIDs were not equal", sent, result); } + + + public void testSendEmptyObjectMessage() throws JMSException + { + ObjectMessage testMessage = _session.createObjectMessage(); + testMessage.setStringProperty("test-property", "test-value"); + assertNotNull("Object was null", testMessage.toString()); + + _producer.send(testMessage); + + ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000); + + assertNotNull("Message was not received.", receivedMessage); + assertNull("No object was sent", receivedMessage.getObject()); + assertEquals("Unexpected property received", "test-value", receivedMessage.getStringProperty("test-property")); + } + } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java index e3557efd97..e7c3fad27d 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java @@ -53,6 +53,10 @@ public class QueuePolicyTest extends QpidBrokerTestCase super.tearDown(); } + /** + * Test Goal : To create a ring queue programitcally with max queue count using the + * address string and observe that it works as expected. + */ public void testRejectPolicy() throws Exception { String addr = "ADDR:queue; {create: always, " + @@ -82,6 +86,10 @@ public class QueuePolicyTest extends QpidBrokerTestCase } } + /** + * Test Goal : To create a ring queue programitcally using the address string and observe + * that it works as expected. + */ public void testRingPolicy() throws Exception { Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); @@ -94,17 +102,18 @@ public class QueuePolicyTest extends QpidBrokerTestCase MessageConsumer consumer = ssn.createConsumer(dest); MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); + _connection.stop(); + prod.send(ssn.createTextMessage("Test1")); prod.send(ssn.createTextMessage("Test2")); prod.send(ssn.createTextMessage("Test3")); + + _connection.start(); TextMessage msg = (TextMessage)consumer.receive(1000); - assertEquals("The consumer should receive the msg with body='Test2'",msg.getText(),"Test2"); + assertEquals("The consumer should receive the msg with body='Test2'","Test2",msg.getText()); msg = (TextMessage)consumer.receive(1000); - assertEquals("The consumer should receive the msg with body='Test3'",msg.getText(),"Test3"); - - prod.send(ssn.createTextMessage("Test4")); - assertEquals("The consumer should receive the msg with body='Test4'",msg.getText(),"Test3"); + assertEquals("The consumer should receive the msg with body='Test3'","Test3",msg.getText()); } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java index 7f166d07fe..20044b7a14 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java @@ -20,19 +20,11 @@ */ package org.apache.qpid.test.unit.client.connection; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.transport.util.Logger; - -import java.util.HashMap; -import java.util.Map; - import javax.jms.Connection; import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; import javax.jms.Session; -import javax.jms.TextMessage; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; /** * ConnectionCloseTest @@ -42,63 +34,6 @@ import javax.jms.TextMessage; public class ConnectionCloseTest extends QpidBrokerTestCase { - private static final Logger log = Logger.get(ConnectionCloseTest.class); - - public void testSendReceiveClose() throws Exception - { - Map<Thread,StackTraceElement[]> before = Thread.getAllStackTraces(); - - for (int i = 0; i < 50; i++) - { - if ((i % 10) == 0) - { - log.warn("%d messages sent and received", i); - } - - Connection receiver = getConnection(); - receiver.start(); - Session rssn = receiver.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = rssn.createQueue("connection-close-test-queue"); - MessageConsumer cons = rssn.createConsumer(queue); - - Connection sender = getConnection(); - sender.start(); - Session sssn = sender.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer prod = sssn.createProducer(queue); - prod.send(sssn.createTextMessage("test")); - sender.close(); - - TextMessage m = (TextMessage) cons.receive(2000); - assertNotNull("message was lost", m); - assertEquals(m.getText(), "test"); - receiver.close(); - } - - // The finalizer is notifying connector thread waiting on a selector key. - // This should leave the finalizer enough time to notify those threads - synchronized (this) - { - this.wait(10000); - } - - Map<Thread,StackTraceElement[]> after = Thread.getAllStackTraces(); - - Map<Thread,StackTraceElement[]> delta = new HashMap<Thread,StackTraceElement[]>(after); - for (Thread t : before.keySet()) - { - delta.remove(t); - } - - dumpStacks(delta); - - int deltaThreshold = (isExternalBroker()? 1 : 2) //InVM creates more thread pools in the same VM - * (Runtime.getRuntime().availableProcessors() + 1) + 5; - - assertTrue("Spurious thread creation exceeded threshold, " + - delta.size() + " threads created.", - delta.size() < deltaThreshold); - } - /** * This test is added due to QPID-3453 to test connection closing when AMQ * session is not closed but underlying transport session is in detached @@ -124,14 +59,4 @@ public class ConnectionCloseTest extends QpidBrokerTestCase } } - private void dumpStacks(Map<Thread,StackTraceElement[]> map) - { - for (Map.Entry<Thread,StackTraceElement[]> entry : map.entrySet()) - { - Throwable t = new Throwable(); - t.setStackTrace(entry.getValue()); - log.warn(t, entry.getKey().toString()); - } - } - } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java index 653ab8f733..3c0f951c96 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java @@ -31,6 +31,8 @@ import org.apache.qpid.test.utils.QpidBrokerTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.jms.Connection; +import javax.jms.IllegalStateException; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; @@ -303,6 +305,70 @@ public class TransactedTest extends QpidBrokerTestCase con2.close(); } + public void testCommitOnClosedConnection() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + connnection.close(); + try + { + transactedSession.commit(); + fail("Commit on closed connection should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + public void testCommitOnClosedSession() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + transactedSession.close(); + try + { + transactedSession.commit(); + fail("Commit on closed session should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + public void testRollbackOnClosedSession() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + transactedSession.close(); + try + { + transactedSession.rollback(); + fail("Rollback on closed session should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + public void testGetTransactedOnClosedSession() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + transactedSession.close(); + try + { + transactedSession.getTransacted(); + fail("According to Sun TCK invocation of Session#getTransacted on closed session should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + private void expect(String text, Message msg) throws JMSException { expect(text, msg, false); diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index 66a20bcfc1..d8c463b810 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -172,3 +172,9 @@ org.apache.qpid.server.management.AMQUserManagementMBeanTest#* // QPID-3133: On 0-10, the exception listener is currently not invoked when reconnection fails to occurs. org.apache.qpid.server.failover.FailoverMethodTest#* +// CPP Broker does not implement non-"shared group" message groups +org.apache.qpid.server.queue.MessageGroupQueueTest#testSimpleGroupAssignment +org.apache.qpid.server.queue.MessageGroupQueueTest#testConsumerCloseGroupAssignment +org.apache.qpid.server.queue.MessageGroupQueueTest#testConsumerCloseWithRelease +org.apache.qpid.server.queue.MessageGroupQueueTest#testGroupAssignmentSurvivesEmpty + diff --git a/qpid/java/test-profiles/Java010Excludes b/qpid/java/test-profiles/Java010Excludes index 59cb5066f1..0de4c6bae5 100755 --- a/qpid/java/test-profiles/Java010Excludes +++ b/qpid/java/test-profiles/Java010Excludes @@ -45,9 +45,6 @@ org.apache.qpid.server.logging.SubscriptionLoggingTest#testSubscriptionSuspend // 0-10 is not supported by the MethodRegistry org.apache.qpid.test.unit.close.JavaServerCloseRaceConditionTest#* -//QPID-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker) -org.apache.qpid.server.queue.ProducerFlowControlTest#* - //QPID-1864: rollback with subscriptions does not work in 0-10 yet org.apache.qpid.test.client.RollbackOrderTest#testOrderingAfterRollbackOnMessage |