[jboss-cvs] JBoss Messaging SVN: r3467 - in trunk: src/main/org/jboss/messaging and 19 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Mon Dec 10 14:01:36 EST 2007
Author: timfox
Date: 2007-12-10 14:01:36 -0500 (Mon, 10 Dec 2007)
New Revision: 3467
Added:
trunk/src/main/org/jboss/messaging/newcore/
trunk/src/main/org/jboss/messaging/newcore/impl/
trunk/src/main/org/jboss/messaging/newcore/impl/MessageImpl.java
trunk/src/main/org/jboss/messaging/newcore/impl/MessageReferenceImpl.java
trunk/src/main/org/jboss/messaging/newcore/impl/QueueImpl.java
trunk/src/main/org/jboss/messaging/newcore/impl/RoundRobinDistributionPolicy.java
trunk/src/main/org/jboss/messaging/newcore/impl/TransactionImpl.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJECursor.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEDatabase.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEEnvironment.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEPersistenceManager.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJETransaction.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEDatabase.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEEnvironment.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJETransaction.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/test/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/test/unit/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/test/unit/RealBDBJEEnvironmentTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEEnvironmentTestBase.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEPersistenceManagerTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBSpeedTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/FakeBDBJEEnvironmentTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/fakes/
trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/fakes/FakeBDBJEEnvironment.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/
trunk/src/main/org/jboss/messaging/newcore/impl/test/concurrent/
trunk/src/main/org/jboss/messaging/newcore/impl/test/concurrent/QueueTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/timing/
trunk/src/main/org/jboss/messaging/newcore/impl/test/timing/QueueTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/MessageTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/QueueTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/RoundRobinDistributionPolicyTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/TransactionTest.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeConsumer.java
trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeFilter.java
trunk/src/main/org/jboss/messaging/newcore/intf/
trunk/src/main/org/jboss/messaging/newcore/intf/ClusteredQueue.java
trunk/src/main/org/jboss/messaging/newcore/intf/Consumer.java
trunk/src/main/org/jboss/messaging/newcore/intf/DistributionPolicy.java
trunk/src/main/org/jboss/messaging/newcore/intf/Filter.java
trunk/src/main/org/jboss/messaging/newcore/intf/HandleStatus.java
trunk/src/main/org/jboss/messaging/newcore/intf/Message.java
trunk/src/main/org/jboss/messaging/newcore/intf/MessageReference.java
trunk/src/main/org/jboss/messaging/newcore/intf/MessagingComponent.java
trunk/src/main/org/jboss/messaging/newcore/intf/PagingManager.java
trunk/src/main/org/jboss/messaging/newcore/intf/PersistenceManager.java
trunk/src/main/org/jboss/messaging/newcore/intf/Queue.java
trunk/src/main/org/jboss/messaging/newcore/intf/QueueStatistics.java
trunk/src/main/org/jboss/messaging/newcore/intf/Transaction.java
trunk/src/main/org/jboss/messaging/newcore/intf/TransactionStore.java
trunk/src/main/org/jboss/messaging/newcore/intf/TransactionSynchronization.java
trunk/src/main/org/jboss/messaging/test/
trunk/src/main/org/jboss/messaging/test/unit/
trunk/src/main/org/jboss/messaging/test/unit/UnitTestCase.java
trunk/tests/lib/easymock.jar
Modified:
trunk/.classpath
trunk/tests/etc/datasource.xml
Log:
First cut at new core
Modified: trunk/.classpath
===================================================================
--- trunk/.classpath 2007-12-10 18:44:52 UTC (rev 3466)
+++ trunk/.classpath 2007-12-10 19:01:36 UTC (rev 3467)
@@ -68,5 +68,7 @@
<classpathentry kind="lib" path="thirdparty/jboss/jbossts14/lib/jbossjta-integration.jar"/>
<classpathentry kind="lib" path="thirdparty/jboss/jboss-javaee/lib/jboss-javaee.jar"/>
<classpathentry kind="lib" path="thirdparty/jboss/jbosssx-client/lib/jbosssx-client.jar"/>
+ <classpathentry kind="lib" path="lib/je-3.2.44.jar"/>
+ <classpathentry kind="lib" path="tests/lib/easymock.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Added: trunk/src/main/org/jboss/messaging/newcore/impl/MessageImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/MessageImpl.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/MessageImpl.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,421 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.logging.Logger;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.util.StreamUtils;
+
+/**
+ * A concrete implementation of a message
+ *
+ * All messages handled by JBM servers are of this type
+ *
+ * @author <a href="mailto:ovidiu at feodorov.com">Ovidiu Feodorov</a>
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 2740 $</tt>
+ *
+ * Note this class is only serializable so messages can be returned from JMX operations
+ * e.g. listAllMessages.
+ *
+ * For normal message transportation serialization is not used
+ *
+ * $Id: MessageSupport.java 2740 2007-05-30 11:36:28Z timfox $
+ */
+public class MessageImpl implements Message
+{
+ // Constants -----------------------------------------------------
+
+ private static final Logger log = Logger.getLogger(MessageImpl.class);
+
+ // Attributes ----------------------------------------------------
+
+ private boolean trace = log.isTraceEnabled();
+
+ private long messageID;
+
+ private int type;
+
+ private boolean reliable;
+
+ /** GMT milliseconds at which this message expires. 0 means never expires * */
+ private long expiration;
+
+ private long timestamp;
+
+ private Map<String, Object> headers;
+
+ private byte priority;
+
+ //The payload of MessageImpl instances is opaque
+ private byte[] payload;
+
+ //We keep track of the persisted references for this message
+ private transient List<MessageReference> references = new ArrayList<MessageReference>();
+
+ private String destination;
+
+ private String connectionID;
+
+ // Constructors --------------------------------------------------
+
+ /*
+ * Construct a message for deserialization or streaming
+ */
+ public MessageImpl()
+ {
+ }
+
+ public MessageImpl(long messageID, int type, boolean reliable, long expiration,
+ long timestamp, byte priority)
+ {
+ this.messageID = messageID;
+ this.type = type;
+ this.reliable = reliable;
+ this.expiration = expiration;
+ this.timestamp = timestamp;
+ this.priority = priority;
+
+ this.headers = new HashMap<String, Object>();
+ }
+
+ /*
+ * Construct a MessageImpl from storage
+ */
+ public MessageImpl(long messageID, int type, boolean reliable, long expiration,
+ long timestamp, byte priority, byte[] headers, byte[] payload)
+ throws Exception
+ {
+ this.messageID = messageID;
+ this.reliable = reliable;
+ this.expiration = expiration;
+ this.timestamp = timestamp;
+ this.priority = priority;
+
+ if (headers == null)
+ {
+ this.headers = new HashMap<String, Object>();
+ }
+ else
+ {
+ //TODO keep headers opaque on server
+ ByteArrayInputStream bis = new ByteArrayInputStream(headers);
+
+ DataInputStream dais = new DataInputStream(bis);
+
+ this.headers = StreamUtils.readMap(dais, true);
+
+ dais.close();
+ }
+ this.payload = payload;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param other
+ */
+ public MessageImpl(MessageImpl other)
+ {
+ this.messageID = other.messageID;
+ this.reliable = other.reliable;
+ this.expiration = other.expiration;
+ this.timestamp = other.timestamp;
+ this.priority = other.priority;
+ this.headers = new HashMap<String, Object>(other.headers);
+ this.payload = other.payload;
+ }
+
+ // Message implementation ----------------------------------------
+
+ public long getMessageID()
+ {
+ return messageID;
+ }
+
+ public void setMessageID(long id)
+ {
+ this.messageID = id;
+ }
+
+ public String getDestination()
+ {
+ return destination;
+ }
+
+ public void setDestination(String destination)
+ {
+ this.destination = destination;
+ }
+
+ public int getType()
+ {
+ return type;
+ }
+
+ public boolean isReliable()
+ {
+ return reliable;
+ }
+
+ public void setReliable(boolean reliable)
+ {
+ this.reliable = reliable;
+ }
+
+ public long getExpiration()
+ {
+ return expiration;
+ }
+
+ public void setExpiration(long expiration)
+ {
+ this.expiration = expiration;
+ }
+
+ public long getTimestamp()
+ {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp)
+ {
+ this.timestamp = timestamp;
+ }
+
+ public Object putHeader(String name, Object value)
+ {
+ return headers.put(name, value);
+ }
+
+ public Object getHeader(String name)
+ {
+ return headers.get(name);
+ }
+
+ public Object removeHeader(String name)
+ {
+ return headers.remove(name);
+ }
+
+ public boolean containsHeader(String name)
+ {
+ return headers.containsKey(name);
+ }
+
+ public Map<String, Object> getHeaders()
+ {
+ return headers;
+ }
+
+ public byte getPriority()
+ {
+ return priority;
+ }
+
+ public void setPriority(byte priority)
+ {
+ this.priority = priority;
+ }
+
+ // TODO - combine with getPayloadAsByteArray to get one big blob
+ public byte[] getHeadersAsByteArray() throws Exception
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
+
+ DataOutputStream oos = new DataOutputStream(bos);
+
+ StreamUtils.writeMap(oos, headers, true);
+
+ oos.close();
+
+ return bos.toByteArray();
+ }
+
+ public byte[] getPayload()
+ {
+ return payload;
+ }
+
+ public void setPayload(byte[] payload)
+ {
+ this.payload = payload;
+ }
+
+ public String getConnectionID()
+ {
+ return connectionID;
+ }
+
+ public void setConnectionID(String connectionID)
+ {
+ this.connectionID = connectionID;
+ }
+
+ public boolean isExpired()
+ {
+ if (expiration == 0)
+ {
+ return false;
+ }
+
+ long overtime = System.currentTimeMillis() - expiration;
+
+ if (overtime >= 0)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public MessageReference createReference(Queue queue)
+ {
+ MessageReference ref = new MessageReferenceImpl(this, queue);
+
+ references.add(ref);
+
+ return ref;
+ }
+
+ public List<MessageReference> getReferences()
+ {
+ return references;
+ }
+
+ public Message copy()
+ {
+ return new MessageImpl(this);
+ }
+
+ // Public --------------------------------------------------------
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o instanceof MessageImpl))
+ {
+ return false;
+ }
+
+ MessageImpl that = (MessageImpl) o;
+
+ return that.messageID == this.messageID;
+ }
+
+ public int hashCode()
+ {
+ return (int) ((this.messageID >>> 32) ^ this.messageID);
+ }
+
+ public String toString()
+ {
+ return "M[" + messageID + "]";
+ }
+
+ // Streamable implementation ---------------------------------
+
+ public void write(DataOutputStream out) throws Exception
+ {
+ out.writeLong(messageID);
+
+ out.writeUTF(destination);
+
+ out.writeInt(type);
+
+ out.writeBoolean(reliable);
+
+ out.writeLong(expiration);
+
+ out.writeLong(timestamp);
+
+ StreamUtils.writeMap(out, headers, true);
+
+ out.writeByte(priority);
+
+ if (payload != null)
+ {
+ out.writeInt(payload.length);
+
+ out.write(payload);
+ }
+ else
+ {
+ out.writeInt(0);
+ }
+ }
+
+ public void read(DataInputStream in) throws Exception
+ {
+ messageID = in.readLong();
+
+ destination = in.readUTF();
+
+ type = in.readInt();
+
+ reliable = in.readBoolean();
+
+ expiration = in.readLong();
+
+ timestamp = in.readLong();
+
+ headers = StreamUtils.readMap(in, true);
+
+ priority = in.readByte();
+
+ int length = in.readInt();
+
+ if (length == 0)
+ {
+ // no payload
+ payload = null;
+ }
+ else
+ {
+ payload = new byte[length];
+
+ in.readFully(payload);
+ }
+ }
+
+ // Package protected ---------------------------------------------
+
+ // Protected -----------------------------------------------------
+
+ // Private -------------------------------------------------------
+
+ // Inner classes -------------------------------------------------
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/MessageReferenceImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/MessageReferenceImpl.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/MessageReferenceImpl.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,132 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl;
+
+import org.jboss.logging.Logger;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+
+/**
+ * Implementation of a MessageReference
+ *
+ * @author <a href="mailto:tim.fox at jboss.com>Tim Fox</a>
+ * @version <tt>1.3</tt>
+ *
+ * MessageReferenceImpl.java,v 1.3 2006/02/23 17:45:57 timfox Exp
+ */
+public class MessageReferenceImpl implements MessageReference
+{
+ private static final Logger log = Logger.getLogger(MessageReferenceImpl.class);
+
+ // Attributes ----------------------------------------------------
+
+ private boolean trace = log.isTraceEnabled();
+
+ private int deliveryCount;
+
+ private long scheduledDeliveryTime;
+
+ private Message message;
+
+ private Queue queue;
+
+ // Constructors --------------------------------------------------
+
+ /**
+ * Required by externalization.
+ */
+ public MessageReferenceImpl()
+ {
+ if (trace) { log.trace("Creating using default constructor"); }
+ }
+
+ public MessageReferenceImpl(MessageReferenceImpl other, Queue queue)
+ {
+ this.deliveryCount = other.deliveryCount;
+
+ this.scheduledDeliveryTime = other.scheduledDeliveryTime;
+
+ this.message = other.message;
+
+ this.queue = queue;
+ }
+
+ protected MessageReferenceImpl(Message message, Queue queue)
+ {
+ this.message = message;
+
+ this.queue = queue;
+ }
+
+ // MessageReference implementation -------------------------------
+
+ public MessageReference copy(Queue queue)
+ {
+ return new MessageReferenceImpl(this, queue);
+ }
+
+ public int getDeliveryCount()
+ {
+ return deliveryCount;
+ }
+
+ public void setDeliveryCount(int deliveryCount)
+ {
+ this.deliveryCount = deliveryCount;
+ }
+
+ public long getScheduledDeliveryTime()
+ {
+ return scheduledDeliveryTime;
+ }
+
+ public void setScheduledDeliveryTime(long scheduledDeliveryTime)
+ {
+ this.scheduledDeliveryTime = scheduledDeliveryTime;
+ }
+
+ public Message getMessage()
+ {
+ return message;
+ }
+
+ public Queue getQueue()
+ {
+ return queue;
+ }
+
+ // Public --------------------------------------------------------
+
+ public String toString()
+ {
+ return "Reference[" + getMessage().getMessageID() + "]:" + (getMessage().isReliable() ? "RELIABLE" : "NON-RELIABLE");
+ }
+
+ // Package protected ---------------------------------------------
+
+ // Protected -----------------------------------------------------
+
+ // Private -------------------------------------------------------
+
+ // Inner classes -------------------------------------------------
+}
\ No newline at end of file
Added: trunk/src/main/org/jboss/messaging/newcore/impl/QueueImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/QueueImpl.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/QueueImpl.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,508 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+
+import org.jboss.jms.server.MessagingTimeoutFactory;
+import org.jboss.logging.Logger;
+import org.jboss.messaging.newcore.intf.Consumer;
+import org.jboss.messaging.newcore.intf.DistributionPolicy;
+import org.jboss.messaging.newcore.intf.Filter;
+import org.jboss.messaging.newcore.intf.HandleStatus;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.util.newprioritylinkedlist.PriorityLinkedList;
+import org.jboss.messaging.util.newprioritylinkedlist.PriorityLinkedListImpl;
+import org.jboss.util.timeout.Timeout;
+import org.jboss.util.timeout.TimeoutTarget;
+
+/**
+ *
+ * A standard non clustered Queue implementation
+ *
+ * TODO use Java 5 concurrent queue
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class QueueImpl implements Queue
+{
+ private static final Logger log = Logger.getLogger(QueueImpl.class);
+
+ private static final boolean trace = log.isTraceEnabled();
+
+ protected long id;
+
+ protected int maxSize = -1;
+
+ protected Filter filter;
+
+ protected PriorityLinkedList<MessageReference> messageReferences;
+
+ protected List<Consumer> consumers;
+
+ protected Set<Timeout> scheduledTimeouts;
+
+ protected DistributionPolicy distributionPolicy;
+
+ protected boolean direct;
+
+ protected boolean promptDelivery;
+
+ private int pos;
+
+ public QueueImpl(long id)
+ {
+ this(id, null);
+ }
+
+ public QueueImpl(long id, Filter filter)
+ {
+ this.id = id;
+
+ this.filter = filter;
+
+ //TODO - use a wait free concurrent queue
+ messageReferences = new PriorityLinkedListImpl<MessageReference>(NUM_PRIORITIES);
+
+ consumers = new ArrayList<Consumer>();
+
+ scheduledTimeouts = new HashSet<Timeout>();
+
+ distributionPolicy = new RoundRobinDistributionPolicy();
+
+ direct = true;
+ }
+
+ public QueueImpl(long id, Filter filter, int maxSize)
+ {
+ this(id, filter);
+
+ this.maxSize = maxSize;
+ }
+
+ // Queue implementation -------------------------------------------------------------------
+
+ public synchronized HandleStatus addLast(MessageReference ref)
+ {
+ return add(ref, false);
+ }
+
+ public synchronized HandleStatus addFirst(MessageReference ref)
+ {
+ return add(ref, true);
+ }
+
+
+ /*
+ * Attempt to deliver all the messages in the queue
+ * @see org.jboss.messaging.newcore.intf.Queue#deliver()
+ */
+ public synchronized void deliver()
+ {
+ MessageReference reference;
+
+ ListIterator<MessageReference> iterator = null;
+
+ while (true)
+ {
+ if (iterator == null)
+ {
+ reference = messageReferences.peekFirst();
+ }
+ else
+ {
+ if (iterator.hasNext())
+ {
+ reference = iterator.next();
+ }
+ else
+ {
+ reference = null;
+ }
+ }
+
+ if (reference == null)
+ {
+ if (iterator == null)
+ {
+ //We delivered all the messages - go into direct delivery
+ direct = true;
+ }
+ return;
+ }
+
+ HandleStatus status = deliver(reference);
+
+ if (status == HandleStatus.HANDLED)
+ {
+ if (iterator == null)
+ {
+ messageReferences.removeFirst();
+ }
+ else
+ {
+ iterator.remove();
+ }
+ }
+ else if (status == HandleStatus.BUSY)
+ {
+ //All consumers busy - give up
+ break;
+ }
+ else if (status == HandleStatus.NO_MATCH && iterator == null)
+ {
+ //Consumers not all busy - but filter not accepting - iterate back through the queue
+ iterator = messageReferences.iterator();
+ }
+ }
+ }
+
+ public synchronized void addConsumer(Consumer consumer)
+ {
+ consumers.add(consumer);
+ }
+
+ public synchronized boolean removeConsumer(Consumer consumer)
+ {
+ boolean removed = consumers.remove(consumer);
+
+ if (pos == consumers.size())
+ {
+ pos = 0;
+ }
+
+ if (consumers.isEmpty())
+ {
+ promptDelivery = false;
+ }
+
+ return removed;
+ }
+
+ public synchronized boolean deliverScheduled(MessageReference reference)
+ {
+ //TODO
+
+ return false;
+ }
+
+ public synchronized int getConsumerCount()
+ {
+ return consumers.size();
+ }
+
+ public synchronized List<MessageReference> list(Filter filter)
+ {
+ if (filter == null)
+ {
+ return new ArrayList<MessageReference>(messageReferences.getAll());
+ }
+ else
+ {
+ ArrayList<MessageReference> list = new ArrayList<MessageReference>();
+
+ for (MessageReference ref: messageReferences.getAll())
+ {
+ if (filter.match(ref.getMessage()))
+ {
+ list.add(ref);
+ }
+ }
+
+ return list;
+ }
+ }
+
+ public synchronized void removeAllReferences()
+ {
+ messageReferences.clear();
+
+ if (!this.scheduledTimeouts.isEmpty())
+ {
+ Set<Timeout> clone = new HashSet<Timeout>(scheduledTimeouts);
+
+ for (Timeout timeout: clone)
+ {
+ timeout.cancel();
+ }
+
+ scheduledTimeouts.clear();
+ }
+ }
+
+ public long getID()
+ {
+ return id;
+ }
+
+ public synchronized Filter getFilter()
+ {
+ return filter;
+ }
+
+ public synchronized void setFilter(Filter filter)
+ {
+ this.filter = filter;
+ }
+
+ public synchronized int getMessageCount()
+ {
+ return messageReferences.size();
+ }
+
+ public synchronized int getScheduledCount()
+ {
+ return scheduledTimeouts.size();
+ }
+
+ public synchronized int getMaxSize()
+ {
+ return maxSize;
+ }
+
+ public synchronized void setMaxSize(int maxSize)
+ {
+ int num = messageReferences.size() + scheduledTimeouts.size();
+
+ if (maxSize < num)
+ {
+ throw new IllegalArgumentException("Cannot set maxSize to " + maxSize + " since there are " + num + " refs");
+ }
+ this.maxSize = maxSize;
+ }
+
+ public synchronized DistributionPolicy getDistributionPolicy()
+ {
+ return distributionPolicy;
+ }
+
+ public synchronized void setDistributionPolicy(DistributionPolicy distributionPolicy)
+ {
+ this.distributionPolicy = distributionPolicy;
+ }
+
+ // Private ------------------------------------------------------------------------------
+
+ private HandleStatus add(MessageReference ref, boolean first)
+ {
+ if (!checkFull())
+ {
+ return HandleStatus.BUSY;
+ }
+
+ if (filter != null)
+ {
+ if (!filter.match(ref.getMessage()))
+ {
+ return HandleStatus.NO_MATCH;
+ }
+ }
+
+ if (!checkAndSchedule(ref))
+ {
+ boolean add = false;
+
+ if (direct)
+ {
+ //Deliver directly
+
+ HandleStatus status = deliver(ref);
+
+ if (status == HandleStatus.HANDLED)
+ {
+ //Ok
+ }
+ else if (status == HandleStatus.BUSY)
+ {
+ add = true;
+ }
+ else if (status == HandleStatus.NO_MATCH)
+ {
+ add = true;
+
+ promptDelivery = true;
+ }
+
+ if (add)
+ {
+ direct = false;
+ }
+ }
+ else
+ {
+ add = true;
+ }
+
+ if (add)
+ {
+ if (first)
+ {
+ messageReferences.addFirst(ref, ref.getMessage().getPriority());
+ }
+ else
+ {
+ messageReferences.addLast(ref, ref.getMessage().getPriority());
+ }
+
+ if (!direct && promptDelivery)
+ {
+ //We have consumers with filters which don't match, so we need to prompt delivery every time
+ //a new message arrives - this is why you really shouldn't use filters with queues - in most cases
+ //it's an ant-pattern since it would cause a queue scan on each message
+ deliver();
+ }
+ }
+ }
+
+ return HandleStatus.HANDLED;
+ }
+
+ private boolean checkAndSchedule(MessageReference ref)
+ {
+ if (ref.getScheduledDeliveryTime() > System.currentTimeMillis())
+ {
+ if (trace) { log.trace("Scheduling delivery for " + ref + " to occur at " + ref.getScheduledDeliveryTime()); }
+
+ // Schedule the cancel to actually occur at the specified time.
+
+ Timeout timeout =
+ MessagingTimeoutFactory.instance.getFactory().
+ schedule(ref.getScheduledDeliveryTime(), new DeliverRefTimeoutTarget(ref));
+
+ scheduledTimeouts.add(timeout);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private boolean checkFull()
+ {
+ if (maxSize != -1 && (messageReferences.size() + scheduledTimeouts.size()) >= maxSize)
+ {
+ if (trace) { log.trace(this + " queue is full, rejecting message"); }
+
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ private HandleStatus deliver(MessageReference reference)
+ {
+ if (consumers.isEmpty())
+ {
+ return HandleStatus.BUSY;
+ }
+
+ int startPos = pos;
+
+ boolean filterRejected = false;
+
+ while (true)
+ {
+ Consumer consumer = consumers.get(pos);
+
+ pos = distributionPolicy.select(consumers, pos);
+
+ HandleStatus status = consumer.handle(reference);
+
+ if (status == HandleStatus.HANDLED)
+ {
+ return HandleStatus.HANDLED;
+ }
+ else if (status == HandleStatus.NO_MATCH)
+ {
+ filterRejected = true;
+ }
+
+ if (pos == startPos)
+ {
+ //Tried all of them
+ if (filterRejected)
+ {
+ return HandleStatus.NO_MATCH;
+ }
+ else
+ {
+ //Give up - all consumers busy
+ return HandleStatus.BUSY;
+ }
+ }
+ }
+ }
+
+ // Inner classes --------------------------------------------------------------------------
+
+ private class DeliverRefTimeoutTarget implements TimeoutTarget
+ {
+ private MessageReference ref;
+
+ public DeliverRefTimeoutTarget(MessageReference ref)
+ {
+ this.ref = ref;
+ }
+
+ public void timedOut(Timeout timeout)
+ {
+ if (trace) { log.trace("Scheduled delivery timeout " + ref); }
+
+ synchronized (scheduledTimeouts)
+ {
+ boolean removed = scheduledTimeouts.remove(timeout);
+
+ if (!removed)
+ {
+ throw new IllegalStateException("Failed to remove timeout " + timeout);
+ }
+ }
+
+ ref.setScheduledDeliveryTime(0);
+
+ HandleStatus status = deliver(ref);
+
+ if (HandleStatus.HANDLED != status)
+ {
+ //Add back to the front of the queue
+
+ addFirst(ref);
+ }
+ else
+ {
+ if (trace) { log.trace("Delivered scheduled delivery at " + System.currentTimeMillis() + " for " + ref); }
+ }
+ }
+ }
+
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/RoundRobinDistributionPolicy.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/RoundRobinDistributionPolicy.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/RoundRobinDistributionPolicy.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl;
+
+import java.util.List;
+
+import org.jboss.messaging.newcore.intf.Consumer;
+import org.jboss.messaging.newcore.intf.DistributionPolicy;
+
+/**
+ *
+ * A RoundRobinDistributionPolicy
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RoundRobinDistributionPolicy implements DistributionPolicy
+{
+ public int select(List<Consumer> consumers, int pos)
+ {
+ if (pos == -1)
+ {
+ //First time
+ pos = 0;
+ }
+ else
+ {
+ pos++;
+
+ if (pos == consumers.size())
+ {
+ pos = 0;
+ }
+ }
+ return pos;
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/TransactionImpl.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/TransactionImpl.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/TransactionImpl.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,181 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.xa.Xid;
+
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.PersistenceManager;
+import org.jboss.messaging.newcore.intf.Transaction;
+import org.jboss.messaging.newcore.intf.TransactionSynchronization;
+
+/**
+ *
+ * A TransactionImpl
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class TransactionImpl implements Transaction
+{
+ private List<Message> messagesToAdd;
+
+ private List<MessageReference> refsToRemove;
+
+ private List<TransactionSynchronization> synchronizations = new ArrayList<TransactionSynchronization>();
+
+ private Xid xid;
+
+ private boolean containsPersistent;
+
+ private boolean prepared;
+
+ public TransactionImpl(List<Message> messagesToAdd, List<MessageReference> refsToRemove,
+ boolean containsPersistent)
+ {
+ this.messagesToAdd = messagesToAdd;
+
+ this.refsToRemove = refsToRemove;
+
+ this.containsPersistent = containsPersistent;
+ }
+
+ public TransactionImpl(Xid xid, List<Message> messagesToAdd, List<MessageReference> refsToRemove,
+ boolean containsPersistent)
+ {
+ this(messagesToAdd, refsToRemove, containsPersistent);
+
+ this.xid = xid;
+ }
+
+ // Transaction implementation -----------------------------------------------------------
+
+ public void addSynchronization(TransactionSynchronization sync)
+ {
+ synchronizations.add(sync);
+ }
+
+ public void prepare(PersistenceManager persistenceManager) throws Exception
+ {
+ if (xid == null)
+ {
+ throw new IllegalStateException("Cannot call prepare() on a non XA transaction");
+ }
+ else
+ {
+ persistenceManager.prepareTransaction(xid, messagesToAdd, refsToRemove);
+
+ prepared = true;
+ }
+ }
+
+ public void commit(PersistenceManager persistenceManager) throws Exception
+ {
+ callSynchronizations(SyncType.BEFORE_COMMIT);
+
+ if (containsPersistent)
+ {
+ if (xid == null)
+ {
+ //1PC commit
+
+ persistenceManager.commitTransaction(messagesToAdd, refsToRemove);
+ }
+ else
+ {
+ //2PC commit
+
+ if (!prepared)
+ {
+ throw new IllegalStateException("Transaction is not prepared");
+ }
+
+ persistenceManager.commitPreparedTransaction(xid);
+ }
+ }
+
+ //Now add to queue(s)
+
+ for (Message msg: messagesToAdd)
+ {
+ for (MessageReference ref: msg.getReferences())
+ {
+ ref.getQueue().addLast(ref);
+ }
+ }
+
+ callSynchronizations(SyncType.AFTER_COMMIT);
+ }
+
+ public void rollback(PersistenceManager persistenceManager) throws Exception
+ {
+ callSynchronizations(SyncType.BEFORE_ROLLBACK);
+
+ if (xid == null)
+ {
+ //1PC rollback - nothing to do
+ }
+ else
+ {
+ persistenceManager.unprepareTransaction(xid, messagesToAdd, refsToRemove);
+ }
+
+ callSynchronizations(SyncType.AFTER_ROLLBACK);
+ }
+
+ // Private -------------------------------------------------------------------
+
+ private void callSynchronizations(SyncType type) throws Exception
+ {
+ for (TransactionSynchronization sync: synchronizations)
+ {
+ if (type == SyncType.BEFORE_COMMIT)
+ {
+ sync.beforeCommit();
+ }
+ else if (type == SyncType.AFTER_COMMIT)
+ {
+ sync.afterCommit();
+ }
+ else if (type == SyncType.BEFORE_ROLLBACK)
+ {
+ sync.beforeRollback();
+ }
+ else if (type == SyncType.AFTER_ROLLBACK)
+ {
+ sync.afterRollback();
+ }
+ }
+ }
+
+ // Inner Enums -------------------------------------------------------------------------------
+
+ private enum SyncType
+ {
+ BEFORE_COMMIT, AFTER_COMMIT, BEFORE_ROLLBACK, AFTER_ROLLBACK;
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJECursor.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJECursor.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJECursor.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.bdbje;
+
+import org.jboss.messaging.util.Pair;
+
+/**
+ *
+ * A CursorIntf
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface BDBJECursor
+{
+ Pair<Long, byte[]> getNext() throws Exception;
+
+ void close() throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEDatabase.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEDatabase.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEDatabase.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,26 @@
+package org.jboss.messaging.newcore.impl.bdbje;
+
+
+/**
+ *
+ * A BDBJEDatabase
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface BDBJEDatabase
+{
+ void put(BDBJETransaction tx, long id, byte[] bytes, int offset, int length) throws Exception;
+
+ void remove(BDBJETransaction tx, long id) throws Exception;
+
+ void close() throws Exception;
+
+ BDBJECursor cursor() throws Exception;
+
+ //Only used for testing
+
+ long size() throws Exception;
+
+ byte[] get(long id) throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEEnvironment.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEEnvironment.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEEnvironment.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,55 @@
+package org.jboss.messaging.newcore.impl.bdbje;
+
+import java.util.List;
+
+import javax.transaction.xa.Xid;
+
+/**
+ *
+ * A BDBJEEnvironment
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface BDBJEEnvironment
+{
+ void start() throws Exception;
+
+ void stop() throws Exception;
+
+ BDBJETransaction createTransaction() throws Exception;
+
+ BDBJEDatabase getDatabase(String databaseName) throws Exception;
+
+ void setEnvironmentPath(String environmentPath);
+
+ String getEnvironmentPath();
+
+ void setTransacted(boolean transacted);
+
+ boolean isTransacted();
+
+ void setSyncVM(boolean sync);
+
+ boolean isSyncVM();
+
+ void setSyncOS(boolean sync);
+
+ boolean isSyncOS();
+
+ void setMemoryCacheSize(long size);
+
+ long getMemoryCacheSize();
+
+ void startWork(Xid xid) throws Exception;
+
+ void endWork(Xid xid, boolean fail) throws Exception;
+
+ void prepare(Xid xid) throws Exception;
+
+ void commit(Xid xid) throws Exception;
+
+ void rollback(Xid xid) throws Exception;
+
+ List<Xid> getInDoubtXids() throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEPersistenceManager.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEPersistenceManager.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJEPersistenceManager.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,555 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.bdbje;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+
+import javax.transaction.xa.Xid;
+
+import org.jboss.logging.Logger;
+import org.jboss.messaging.newcore.impl.MessageImpl;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.PersistenceManager;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.util.Pair;
+
+/**
+ *
+ * A PersistenceManager implementation that stores messages using Berkeley DB Java Edition.
+ *
+ * We store message data in one BDB JE Database and MessageReference data in another.
+ *
+ * Both Database instances are in the same BDB JE Environment. All database in a single environment
+ * share the same log file and can participate in the same transaction.
+ *
+ * We store MessageReference data in a different Database since currently BDB JE is not optimised for partial
+ * updates - this means if we have a large message, then for every MessageReference we would have to update
+ * and store the entire message again - once for each reference as they are delivered / acknowldeged - this
+ * can give very poor performance.
+ *
+ * TODO - Optimisation - If there is only one MessageReference per Message then we can store it in the same database
+ *
+ * For XA functionality we do not write explicit transaction records as it proves somewhat quicker to rely
+ * on BDB JE's inbuilt XA transaction capability.
+ *
+ * If messages are larger than <minLargeMessageSize> the messages are not stored in the BDB log but are stored
+ * as individual files in the <largeMessageRepositoryPath> directory referenced by a pointer from
+ * the log. This is because storing very large messages in a BDB log is not an efficient use of the log.
+ *
+ * @author <a href="tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class BDBJEPersistenceManager implements PersistenceManager
+{
+ private static final Logger log = Logger.getLogger(BDBJEPersistenceManager.class);
+
+ private static final boolean trace = log.isTraceEnabled();
+
+ private static final int SIZE_LONG = 8;
+
+ private static final int SIZE_INT = 4;
+
+ private static final int SIZE_BYTE = 1;
+
+ public static final int SIZE_REF_DATA =
+ SIZE_LONG + SIZE_INT + SIZE_LONG; // queue id + delivery count + scheduled delivery
+
+ // type + expiration + timestamp + priority
+ public static final int SIZE_FIELDS = SIZE_INT + SIZE_LONG + SIZE_LONG + SIZE_BYTE;
+
+ private static final byte[] ZERO_LENGTH_BYTE_ARRAY = new byte[0];
+
+ public static final String MESSAGE_DB_NAME = "message";
+
+ public static final String REFERENCE_DB_NAME = "reference";
+
+ private boolean recovery;
+
+ private BDBJEEnvironment environment;
+
+ private BDBJEDatabase messageDB;
+
+ private BDBJEDatabase refDB;
+
+ private String largeMessageRepositoryPath;
+
+ private int minLargeMessageSize;
+
+ private String environmentPath;
+
+ private boolean started;
+
+ public BDBJEPersistenceManager(BDBJEEnvironment environment, String environmentPath)
+ {
+ this.environment = environment;
+
+ this.environmentPath = environmentPath;
+ }
+
+ // MessagingComponent implementation -----------------------------------------------------
+
+ public synchronized void start() throws Exception
+ {
+ if (started)
+ {
+ return;
+ }
+
+ environment.setEnvironmentPath(environmentPath);
+
+ environment.start();
+
+ messageDB = environment.getDatabase(MESSAGE_DB_NAME);
+
+ refDB = environment.getDatabase(REFERENCE_DB_NAME);
+
+ started = true;
+ }
+
+ public synchronized void stop() throws Exception
+ {
+ if (!started)
+ {
+ return;
+ }
+
+ messageDB.close();
+
+ refDB.close();
+
+ environment.stop();
+
+ recovery = false;
+
+ started = false;
+ }
+
+ // PersistenceManager implementation ----------------------------------------------------------
+
+ public void addMessage(Message message) throws Exception
+ {
+ BDBJETransaction tx = null;
+
+ try
+ {
+ tx = environment.createTransaction();
+
+ internalCommitMessage(tx, message);
+
+ tx.commit();
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ if (tx != null)
+ {
+ tx.rollback();
+ }
+ }
+ catch (Throwable ignore)
+ {
+ if (trace) { log.trace("Failed to rollback", ignore); }
+ }
+ }
+ }
+
+ public void commitTransaction(List<Message> messagesToAdd,
+ List<MessageReference> referencesToRemove) throws Exception
+ {
+
+ BDBJETransaction tx = null;
+
+ try
+ {
+ tx = environment.createTransaction();
+
+ playTx(tx, messagesToAdd, referencesToRemove);
+
+ tx.commit();
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ if (tx != null)
+ {
+ tx.rollback();
+ }
+ }
+ catch (Throwable ignore)
+ {
+ if (trace) { log.trace("Failed to rollback", ignore); }
+ }
+ }
+ }
+
+ public void prepareTransaction(Xid xid, List<Message> messagesToAdd,
+ List<MessageReference> referencesToRemove) throws Exception
+ {
+ environment.startWork(xid);
+
+ try
+ {
+ playTx(null, messagesToAdd, referencesToRemove);
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ environment.endWork(xid, true);
+ }
+ catch (Throwable ignore)
+ {
+ if (trace) { log.trace("Failed to end", ignore); }
+ }
+
+ throw e;
+ }
+
+ environment.endWork(xid, false);
+
+ environment.prepare(xid);
+ }
+
+ public void commitPreparedTransaction(Xid xid) throws Exception
+ {
+ environment.commit(xid);
+ }
+
+ public void unprepareTransaction(Xid xid, List<Message> messagesToAdd,
+ List<MessageReference> referencesToRemove) throws Exception
+ {
+ environment.rollback(xid);
+ }
+
+ public void deleteReference(MessageReference reference)
+ {
+ BDBJETransaction tx = null;
+
+ try
+ {
+ tx = environment.createTransaction();
+
+ internalDeleteReference(tx, reference);
+
+ tx.commit();
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ if (tx != null)
+ {
+ tx.rollback();
+ }
+ }
+ catch (Throwable ignore)
+ {
+ if (trace) { log.trace("Failed to rollback", ignore); }
+ }
+ }
+ }
+
+ public List<Xid> getInDoubtXids() throws Exception
+ {
+ if (!recovery)
+ {
+ throw new IllegalStateException("Must be in recovery mode to call getInDoubtXids()");
+ }
+
+ return environment.getInDoubtXids();
+ }
+
+ public void setInRecoveryMode(boolean recoveryMode)
+ {
+ this.recovery = recoveryMode;
+ }
+
+ public boolean isInRecoveryMode()
+ {
+ return recovery;
+ }
+
+ public void loadQueues(Map<Long, Queue> queues) throws Exception
+ {
+ BDBJECursor cursorMessage = null;
+
+ BDBJECursor cursorRef = null;
+
+ try
+ {
+ cursorMessage = messageDB.cursor();
+
+ cursorRef = refDB.cursor();
+
+ Pair<Long, byte[]> messagePair;
+
+ Pair<Long, byte[]> refPair;
+
+ while ((messagePair = cursorMessage.getNext()) != null)
+ {
+ refPair = cursorRef.getNext();
+
+ if (refPair == null)
+ {
+ throw new IllegalStateException("Message and ref data out of sync");
+ }
+
+ long id = messagePair.a;
+
+ byte[] bytes = messagePair.b;
+
+ ByteBuffer buffer = ByteBuffer.wrap(bytes);
+
+ int type = buffer.getInt();
+
+ long expiration = buffer.getLong();
+
+ long timestamp = buffer.getLong();
+
+ byte priority = buffer.get();
+
+ int headerSize = buffer.getInt();
+
+ //TODO we can optimise this to prevent a copy - let the message use a window on the byte[]
+
+ byte[] headers = new byte[headerSize];
+
+ buffer.get(headers);
+
+ int payloadSize = buffer.getInt();
+
+ byte[] payload = new byte[payloadSize];
+
+ buffer.get(payload);
+
+ Message message = new MessageImpl(id, type, true, expiration, timestamp, priority,
+ headers, payload);
+
+ //Now the ref data
+
+ byte[] refBytes = refPair.b;
+
+ buffer = ByteBuffer.wrap(refBytes);
+
+ while (buffer.hasRemaining())
+ {
+ long queueID = buffer.getLong();
+
+ int deliveryCount = buffer.getInt();
+
+ long scheduledDeliveryTime = buffer.getLong();
+
+ Queue queue = queues.get(queueID);
+
+ if (queue == null)
+ {
+ //Ok - queue is not deployed
+ }
+ else
+ {
+ MessageReference reference = message.createReference(queue);
+
+ reference.setDeliveryCount(deliveryCount);
+
+ reference.setScheduledDeliveryTime(scheduledDeliveryTime);
+
+ queue.addLast(reference);
+ }
+ }
+ }
+ }
+ finally
+ {
+ if (cursorMessage != null)
+ {
+ cursorMessage.close();
+ }
+
+ if (cursorRef != null)
+ {
+ cursorRef.close();
+ }
+ }
+ }
+
+ public void updateDeliveryCount(Queue queue, MessageReference ref) throws Exception
+ {
+ //TODO - optimise this scan
+
+ int pos = ref.getMessage().getReferences().indexOf(ref);
+
+ int offset = pos * SIZE_REF_DATA + SIZE_LONG;
+
+ byte[] bytes = new byte[SIZE_INT];
+
+ ByteBuffer buff = ByteBuffer.wrap(bytes);
+
+ buff.putInt(ref.getDeliveryCount());
+
+ refDB.put(null, ref.getMessage().getMessageID(), bytes, offset, SIZE_INT);
+ }
+
+ // Public ----------------------------------------------------------------------------------
+
+ public String getLargeMessageRepositoryPath()
+ {
+ return largeMessageRepositoryPath;
+ }
+
+ public void setLargeMessageRepository(String largeMessageRepositoryPath)
+ {
+ this.largeMessageRepositoryPath = largeMessageRepositoryPath;
+ }
+
+ public int getMinLargeMessageSize()
+ {
+ return minLargeMessageSize;
+ }
+
+ public void setMinLargeMessageSize(int minLargeMessageSize)
+ {
+ this.minLargeMessageSize = minLargeMessageSize;
+ }
+
+ public boolean isStarted()
+ {
+ return started;
+ }
+
+ public void setStarted(boolean started)
+ {
+ this.started = started;
+ }
+
+ // Private ---------------------------------------------------------------------------------
+
+ private void playTx(BDBJETransaction tx, List<Message> messagesToAdd,
+ List<MessageReference> referencesToRemove) throws Exception
+ {
+ if (messagesToAdd != null)
+ {
+ for (Message message: messagesToAdd)
+ {
+ internalCommitMessage(tx, message);
+ }
+ }
+
+ if (referencesToRemove != null)
+ {
+ for (MessageReference ref: referencesToRemove)
+ {
+ internalDeleteReference(tx, ref);
+ }
+ }
+ }
+
+ private void internalCommitMessage(BDBJETransaction tx, Message message) throws Exception
+ {
+ //First store the message
+
+ byte[] headers = message.getHeadersAsByteArray();
+
+ int headersLength = headers.length;
+
+ byte[] payload = message.getPayload();
+
+ int payloadLength = payload == null ? 0 : payload.length;
+
+ //TODO - avoid copying by having message already store it's byte representation or do partial
+ //update in BDB
+ byte[] bytes = new byte[SIZE_FIELDS + 2 * SIZE_INT + headersLength + payloadLength];
+
+ ByteBuffer buffer = ByteBuffer.wrap(bytes);
+
+ //Put the fields
+ buffer.putInt(message.getType());
+ buffer.putLong(message.getExpiration());
+ buffer.putLong(message.getTimestamp());
+ buffer.put(message.getPriority());
+
+ buffer.putInt(headersLength);
+ buffer.put(headers);
+
+ buffer.putInt(payloadLength);
+ if (payload != null)
+ {
+ buffer.put(payload);
+ }
+
+ //Now the ref(s)
+
+ byte[] refBytes = new byte[message.getReferences().size() * SIZE_REF_DATA];
+
+ ByteBuffer buff = ByteBuffer.wrap(refBytes);
+
+ for (MessageReference ref: message.getReferences())
+ {
+ buff.putLong(ref.getQueue().getID());
+ buff.putInt(ref.getDeliveryCount());
+ buff.putLong(ref.getScheduledDeliveryTime());
+ }
+
+ try
+ {
+ messageDB.put(tx, message.getMessageID(), bytes, 0, bytes.length);
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace();
+ }
+
+ refDB.put(tx, message.getMessageID(), refBytes, 0, refBytes.length);
+ }
+
+ private void internalDeleteReference(BDBJETransaction tx, MessageReference reference) throws Exception
+ {
+ Message message = reference.getMessage();
+
+ boolean deleteAll = message.getReferences().size() == 1;
+
+ if (deleteAll)
+ {
+ refDB.remove(tx, message.getMessageID());
+
+ messageDB.remove(tx, message.getMessageID());
+
+ message.getReferences().remove(0);
+ }
+ else
+ {
+ //TODO - this can be optimised so not to scan using indexOf
+
+ int pos = message.getReferences().indexOf(reference);
+
+ int offset = pos * SIZE_REF_DATA;
+
+ refDB.put(tx, message.getMessageID(), ZERO_LENGTH_BYTE_ARRAY, offset, SIZE_REF_DATA);
+
+ message.getReferences().remove(pos);
+ }
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJETransaction.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJETransaction.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/BDBJETransaction.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,15 @@
+package org.jboss.messaging.newcore.impl.bdbje;
+
+/**
+ *
+ * A BDBJETransaction
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface BDBJETransaction
+{
+ public void commit() throws Exception;
+
+ public void rollback() throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEDatabase.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEDatabase.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEDatabase.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,161 @@
+package org.jboss.messaging.newcore.impl.bdbje.integration;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJECursor;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEDatabase;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJETransaction;
+import org.jboss.messaging.util.Pair;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.tuple.LongBinding;
+import com.sleepycat.je.Cursor;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.LockMode;
+import com.sleepycat.je.OperationStatus;
+import com.sleepycat.je.Transaction;
+
+/**
+ *
+ * A RealBDBJEDatabase
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealBDBJEDatabase implements BDBJEDatabase
+{
+ private Database database;
+
+ RealBDBJEDatabase(Database database)
+ {
+ this.database = database;
+ }
+
+ // BDBJEDatabase implementation ------------------------------------------
+
+ public void put(BDBJETransaction tx, long id, byte[] bytes, int offset, int length) throws Exception
+ {
+ DatabaseEntry key = createKey(id);
+
+ DatabaseEntry value = new DatabaseEntry();
+
+ if (offset != 0)
+ {
+ value.setPartial(offset, length, true);
+ }
+
+ value.setData(bytes);
+
+ Transaction bdbTx = getBDBTx(tx);
+
+ database.put(bdbTx, key, value);
+ }
+
+ public void remove(BDBJETransaction tx, long id) throws Exception
+ {
+ DatabaseEntry key = createKey(id);
+
+ Transaction bdbTx = getBDBTx(tx);
+
+ database.delete(bdbTx, key);
+ }
+
+ public BDBJECursor cursor() throws Exception
+ {
+ return new RealBDBJECursor();
+ }
+
+ public void close() throws Exception
+ {
+ database.close();
+ }
+
+ // For testing
+
+ public byte[] get(long id) throws Exception
+ {
+ DatabaseEntry key = createKey(id);
+
+ DatabaseEntry data = new DatabaseEntry();
+
+ if (database.get(null, key, data, LockMode.DEFAULT) != OperationStatus.SUCCESS)
+ {
+ return null;
+ }
+ else
+ {
+ return data.getData();
+ }
+ }
+
+ public long size() throws Exception
+ {
+ return database.count();
+ }
+
+ // Private ----------------------------------------------------------------------
+
+ private DatabaseEntry createKey(long id)
+ {
+ DatabaseEntry key = new DatabaseEntry();
+
+ EntryBinding keyBinding = new LongBinding();
+
+ keyBinding.objectToEntry(id, key);
+
+ return key;
+ }
+
+ private Transaction getBDBTx(BDBJETransaction tx)
+ {
+ Transaction bdbTx = null;
+
+ if (tx != null)
+ {
+ RealBDBJETransaction bdbJETx = (RealBDBJETransaction)tx;
+
+ bdbTx = bdbJETx.getTransaction();
+ }
+
+ return bdbTx;
+ }
+
+ // Inner classes ---------------------------------------------------------------------
+
+ private class RealBDBJECursor implements BDBJECursor
+ {
+ private Cursor cursor;
+
+ RealBDBJECursor() throws Exception
+ {
+ cursor = database.openCursor(null, null);
+ }
+
+ public Pair<Long, byte[]> getNext() throws Exception
+ {
+ DatabaseEntry key = new DatabaseEntry();
+
+ DatabaseEntry data = new DatabaseEntry();
+
+ if (cursor.getNext(key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS)
+ {
+ long id = LongBinding.entryToLong(key);
+
+ byte[] bytes = data.getData();
+
+ Pair<Long, byte[]> pair = new Pair<Long, byte[]>(id, bytes);
+
+ return pair;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void close() throws Exception
+ {
+ cursor.close();
+ }
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEEnvironment.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEEnvironment.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJEEnvironment.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,390 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.bdbje.integration;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEDatabase;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJETransaction;
+
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.je.XAEnvironment;
+
+/**
+ *
+ * A RealBDBJEEnvironment
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealBDBJEEnvironment implements BDBJEEnvironment
+{
+ /**
+ * The actual DB environment
+ */
+ private XAEnvironment environment;
+
+ /**
+ * The path of the environment
+ */
+ private String environmentPath;
+
+ /**
+ * Is the environment transacted?
+ */
+ private boolean transacted;
+
+ /**
+ * Do we sync OS buffers to disk on transaction commit?
+ */
+ private boolean syncOS;
+
+ /**
+ * Do we sync to the OS on transaction commit ?
+ */
+ private boolean syncVM;
+
+ /**
+ * Memory cache size in bytes, or -1 to use BDB default
+ *
+ */
+ private long memoryCacheSize = -1;
+
+ /**
+ * Are we started?
+ */
+ private volatile boolean started;
+
+ /**
+ * Are we in debug mode? Used in testing
+ */
+ private boolean debug;
+
+ /**
+ * Used for debug only to ensure the XA operations are called in the right order
+ */
+ private Map<Thread, ThreadTXStatus> threadTXStatuses;
+
+ public RealBDBJEEnvironment(boolean debug)
+ {
+ this.debug = debug;
+
+ if (debug)
+ {
+ threadTXStatuses = new ConcurrentHashMap<Thread, ThreadTXStatus>();
+ }
+ }
+
+ public synchronized void start() throws Exception
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Already started");
+ }
+ if (environmentPath == null)
+ {
+ throw new IllegalStateException("environmentPath has not been specified");
+ }
+
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+
+ if (memoryCacheSize != -1)
+ {
+ envConfig.setCacheSize(memoryCacheSize);
+ }
+
+ envConfig.setTxnNoSync(!syncOS);
+
+ envConfig.setTxnWriteNoSync(!syncVM);
+
+ envConfig.setAllowCreate(true);
+
+ envConfig.setTransactional(transacted);
+
+ environment = new XAEnvironment(new File(environmentPath), envConfig);
+
+ DatabaseConfig dbConfig = new DatabaseConfig();
+
+ dbConfig.setTransactional(transacted);
+
+ dbConfig.setAllowCreate(true);
+
+ started = true;
+ }
+
+ public synchronized void stop() throws Exception
+ {
+ if (!started)
+ {
+ throw new IllegalStateException("Not started");
+ }
+
+ try
+ {
+ environment.close();
+ }
+ catch (Exception ignore)
+ {
+ //Environment close might fail since there are open transactions - this is ok
+ }
+
+ started = false;
+ }
+
+ public BDBJETransaction createTransaction() throws Exception
+ {
+ return new RealBDBJETransaction(environment.beginTransaction(null, null));
+ }
+
+ public BDBJEDatabase getDatabase(String databaseName) throws Exception
+ {
+ DatabaseConfig dbConfig = new DatabaseConfig();
+
+ dbConfig.setTransactional(transacted);
+
+ dbConfig.setAllowCreate(true);
+
+ Database database = environment.openDatabase(null, databaseName, dbConfig);
+
+ BDBJEDatabase db = new RealBDBJEDatabase(database);
+
+ return db;
+ }
+
+ public String getEnvironmentPath()
+ {
+ return this.environmentPath;
+ }
+
+ public long getMemoryCacheSize()
+ {
+ return this.memoryCacheSize;
+ }
+
+ public boolean isSyncOS()
+ {
+ return this.syncOS;
+ }
+
+ public boolean isSyncVM()
+ {
+ return this.syncVM;
+ }
+
+ public boolean isTransacted()
+ {
+ return this.transacted;
+ }
+
+ public void setEnvironmentPath(String environmentPath)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set EnvironmentPath when started");
+ }
+ this.environmentPath = environmentPath;
+ }
+
+ public void setMemoryCacheSize(long size)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set MemoryCacheSize when started");
+ }
+ this.memoryCacheSize = size;
+ }
+
+ public void setSyncOS(boolean sync)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set SyncOS when started");
+ }
+ this.syncOS = sync;
+ }
+
+ public void setSyncVM(boolean sync)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set SyncVM when started");
+ }
+ this.syncVM = sync;
+ }
+
+ public void setTransacted(boolean transacted)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set Transacted when started");
+ }
+ this.transacted = transacted;
+ }
+
+ public List<Xid> getInDoubtXids() throws Exception
+ {
+ Xid[] xids = environment.recover(XAResource.TMSTARTRSCAN);
+
+ List<Xid> list = Arrays.asList(xids);
+
+ return list;
+ }
+
+ public void startWork(Xid xid) throws Exception
+ {
+ if (debug)
+ {
+ checkNoStatus();
+
+ threadTXStatuses.put(Thread.currentThread(), new ThreadTXStatus(xid));
+ }
+
+ environment.start(xid, XAResource.TMNOFLAGS);
+ }
+
+ public void endWork(Xid xid, boolean failed) throws Exception
+ {
+ if (debug)
+ {
+ checkXAState(xid, XAState.IN_WORK);
+
+ setXAState(XAState.DONE_WORK);
+ }
+
+ environment.end(xid, failed ? XAResource.TMFAIL : XAResource.TMSUCCESS);
+ }
+
+ public void prepare(Xid xid) throws Exception
+ {
+ if (debug)
+ {
+ checkXAState(xid, XAState.DONE_WORK);
+
+ setXAState(XAState.PREPARE_CALLED);
+ }
+
+ environment.prepare(xid);
+ }
+
+ public void commit(Xid xid) throws Exception
+ {
+ if (debug)
+ {
+ checkXAState(xid, XAState.PREPARE_CALLED);
+
+ threadTXStatuses.remove(Thread.currentThread());
+ }
+
+ environment.commit(xid, false);
+ }
+
+ public void rollback(Xid xid) throws Exception
+ {
+ if (debug)
+ {
+ checkXAState(xid, XAState.PREPARE_CALLED);
+
+ threadTXStatuses.remove(Thread.currentThread());
+ }
+
+ environment.rollback(xid);
+ }
+
+ // Private -------------------------------------------------------------------------
+
+ /*
+ * Used for debug only
+ */
+ private ThreadTXStatus getTxStatus()
+ {
+ return threadTXStatuses.get(Thread.currentThread());
+ }
+
+ private void checkXAState(Xid xid, XAState state)
+ {
+ ThreadTXStatus status = getTxStatus();
+
+ if (status == null)
+ {
+ throw new IllegalStateException("Not started any xa work");
+ }
+
+ if (!state.equals(status.state))
+ {
+ throw new IllegalStateException("Invalid XAState expected " + state + " got " + status.state);
+ }
+
+ if (xid != status.implicitXid)
+ {
+ throw new IllegalStateException("Wrong xid");
+ }
+ }
+
+ private void checkNoStatus()
+ {
+ ThreadTXStatus status = getTxStatus();
+
+ if (status != null)
+ {
+ throw new IllegalStateException("XA status should not exist");
+ }
+ }
+
+ private void setXAState(XAState state)
+ {
+ threadTXStatuses.get(Thread.currentThread()).state = state;
+ }
+
+
+ // Inner classes --------------------------------------------------------------------
+
+ private enum XAState
+ {
+ NOT_STARTED, IN_WORK, DONE_WORK, PREPARE_CALLED
+ }
+
+ /*
+ * Used for debug only
+ */
+ private class ThreadTXStatus
+ {
+ ThreadTXStatus(Xid xid)
+ {
+ this.implicitXid = xid;
+ }
+
+ Xid implicitXid;
+
+ XAState state = XAState.IN_WORK;
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJETransaction.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJETransaction.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/RealBDBJETransaction.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,38 @@
+package org.jboss.messaging.newcore.impl.bdbje.integration;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJETransaction;
+
+import com.sleepycat.je.Transaction;
+
+/**
+ *
+ * A RealBDBJETransaction
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealBDBJETransaction implements BDBJETransaction
+{
+ private Transaction transaction;
+
+ RealBDBJETransaction(Transaction transaction)
+ {
+ this.transaction = transaction;
+ }
+
+ public void commit() throws Exception
+ {
+ transaction.commit();
+ }
+
+ public void rollback() throws Exception
+ {
+ transaction.abort();
+ }
+
+ public Transaction getTransaction()
+ {
+ return transaction;
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/test/unit/RealBDBJEEnvironmentTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/test/unit/RealBDBJEEnvironmentTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/integration/test/unit/RealBDBJEEnvironmentTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,48 @@
+package org.jboss.messaging.newcore.impl.bdbje.integration.test.unit;
+
+import java.io.File;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.integration.RealBDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.test.unit.BDBJEEnvironmentTestBase;
+
+/**
+ *
+ * A RealBDBJEEnvironmentTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RealBDBJEEnvironmentTest extends BDBJEEnvironmentTestBase
+{
+ protected void setUp() throws Exception
+ {
+ createDir(ENV_DIR);
+
+ env = createEnvironment();
+
+ env.setEnvironmentPath(ENV_DIR);
+
+ env.start();
+
+ database = env.getDatabase("test-db");
+ }
+
+ protected BDBJEEnvironment createEnvironment() throws Exception
+ {
+ BDBJEEnvironment env = new RealBDBJEEnvironment(true);
+
+ env.setTransacted(true);
+
+ return env;
+ }
+
+ protected void createDir(String path)
+ {
+ File file = new File(path);
+
+ deleteDirectory(file);
+
+ file.mkdir();
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEEnvironmentTestBase.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEEnvironmentTestBase.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEEnvironmentTestBase.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,1726 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.bdbje.test.unit;
+
+import java.util.List;
+
+import javax.transaction.xa.Xid;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEDatabase;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJETransaction;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * Base for tests for BDBJEEnvironment and BDBJEDatabase
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public abstract class BDBJEEnvironmentTestBase extends UnitTestCase
+{
+ protected BDBJEEnvironment env;
+
+ protected BDBJEDatabase database;
+
+ protected static final String ENV_DIR = "test-bdb-environment";
+
+ protected static final String DB_NAME = "test-db";
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ env = createEnvironment();
+
+ env.setEnvironmentPath(ENV_DIR);
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+ }
+
+ protected abstract void createDir(String path);
+
+ protected void tearDown() throws Exception
+ {
+ database.close();
+
+ env.stop();
+ }
+
+ protected abstract BDBJEEnvironment createEnvironment() throws Exception;
+
+ // The tests ----------------------------------------------------------------
+
+ public void testGetInDoubtXidsCompleteWithCommit() throws Exception
+ {
+ List<Xid> xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+
+ Xid xid1 = generateXid();
+
+ env.startWork(xid1);
+
+ database.put(null, 1, new byte[10], 0, 10);
+
+ env.endWork(xid1, false);
+
+ env.prepare(xid1);
+
+ xids = env.getInDoubtXids();
+
+ assertEquals(xid1, xids.get(0));
+
+ env.commit(xid1);
+
+ xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+ }
+
+ public void testGetInDoubtXidsCompleteWithRollback() throws Exception
+ {
+ List<Xid> xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+
+ Xid xid1 = generateXid();
+
+ env.startWork(xid1);
+
+ database.put(null, 1, new byte[10], 0, 10);
+
+ env.endWork(xid1, false);
+
+ env.prepare(xid1);
+
+ xids = env.getInDoubtXids();
+
+ assertEquals(xid1, xids.get(0));
+
+ env.rollback(xid1);
+
+ xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+ }
+
+
+ public void testGetInDoubtXidsMultiple() throws Exception
+ {
+ List<Xid> xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+
+ Xid xid1 = generateXid();
+ env.startWork(xid1);
+ database.put(null, 1, new byte[10], 0, 10);
+ env.endWork(xid1, false);
+
+ env.prepare(xid1);
+ xids = env.getInDoubtXids();
+ assertEquals(xid1, xids.get(0));
+
+
+ Xid xid2 = generateXid();
+ env.startWork(xid2);
+ database.put(null, 1, new byte[10], 0, 10);
+ env.endWork(xid2, false);
+
+ env.prepare(xid2);
+ xids = env.getInDoubtXids();
+ assertTrue(xids.contains(xid1));
+ assertTrue(xids.contains(xid2));
+
+ Xid xid3 = generateXid();
+ env.startWork(xid3);
+ database.put(null, 1, new byte[10], 0, 10);
+ env.endWork(xid3, false);
+
+ env.prepare(xid3);
+ xids = env.getInDoubtXids();
+ assertTrue(xids.contains(xid1));
+ assertTrue(xids.contains(xid2));
+ assertTrue(xids.contains(xid3));
+
+ }
+
+ public void testGetInDoubtXidsMultipleWithRestart() throws Exception
+ {
+ List<Xid> xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+
+ Xid xid1 = generateXid();
+ env.startWork(xid1);
+ database.put(null, 1, new byte[10], 0, 10);
+ env.endWork(xid1, false);
+
+ env.prepare(xid1);
+ xids = env.getInDoubtXids();
+ assertEquals(xid1, xids.get(0));
+
+
+ Xid xid2 = generateXid();
+ env.startWork(xid2);
+ database.put(null, 1, new byte[10], 0, 10);
+ env.endWork(xid2, false);
+
+ env.prepare(xid2);
+ xids = env.getInDoubtXids();
+ assertTrue(xids.contains(xid1));
+ assertTrue(xids.contains(xid2));
+
+ Xid xid3 = generateXid();
+ env.startWork(xid3);
+ database.put(null, 1, new byte[10], 0, 10);
+ env.endWork(xid3, false);
+
+ env.prepare(xid3);
+ xids = env.getInDoubtXids();
+ assertTrue(xids.contains(xid1));
+ assertTrue(xids.contains(xid2));
+ assertTrue(xids.contains(xid3));
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ xids = env.getInDoubtXids();
+ assertTrue(xids.contains(xid1));
+ assertTrue(xids.contains(xid2));
+ assertTrue(xids.contains(xid3));
+
+ env.commit(xid1);
+ env.commit(xid2);
+ env.commit(xid3);
+
+ xids = env.getInDoubtXids();
+
+ assertTrue(xids.isEmpty());
+ }
+
+ public void testPutAndRemoveNonTransactional() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutAndRemoveNonTransactionalWithRestart() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertContainsPair(id, bytes, 1);
+ }
+
+ public void testPutAndRemoveMultipleNonTransactional() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ byte[] bytes3 = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
+
+ long id1 = 1;
+
+ long id2 = 2;
+
+ long id3 = 3;
+
+ int offset = 0;
+
+ database.put(null, id1, bytes1, offset, bytes1.length);
+
+ database.put(null, id2, bytes2, offset, bytes2.length);
+
+ database.put(null, id3, bytes3, offset, bytes3.length);
+
+ assertContainsPair(id1, bytes1, 3);
+
+ assertContainsPair(id2, bytes2, 3);
+
+ assertContainsPair(id3, bytes3, 3);
+
+ database.remove(null, id2);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id3, bytes3, 2);
+
+ database.remove(null, id3);
+
+ assertContainsPair(id1, bytes1, 1);
+
+ database.remove(null, id1);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutTransactionalCommit() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id, bytes, offset, bytes.length);
+
+ tx.commit();
+
+ assertContainsPair(id, bytes, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutTransactionalWithRestart() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id, bytes, offset, bytes.length);
+
+ //Now restart before committing
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutXACommit() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.commit(xid);
+
+ assertContainsPair(id, bytes, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutXAWithRestart() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ env.endWork(xid, false);
+
+ // Now restart
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertStoreEmpty();
+ }
+
+
+ public void testPutXAWithRestartAfterPrepare() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ // Now restart
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertStoreEmpty();
+ }
+
+ public void testRemoveTransactional() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.remove(tx, id);
+
+ tx.commit();
+
+ assertStoreEmpty();
+ }
+
+ public void testRemoveTransactionalWithRestart() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.remove(tx, id);
+
+ // Now restart
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertContainsPair(id, bytes, 1);
+ }
+
+ public void testRemoveXACommit() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.remove(null, id);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.commit(xid);
+
+ assertStoreEmpty();
+ }
+
+ public void testRemoveXAWithRestart() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.remove(null, id);
+
+ env.endWork(xid, false);
+
+ // Now restart
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertContainsPair(id, bytes, 1);
+ }
+
+ public void testRemoveXAWithRestartAfterPrepare() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.remove(null, id);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ // Now restart
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertContainsPair(id, bytes, 1);
+ }
+
+ public void testPutTransactionalRollback() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id, bytes, offset, bytes.length);
+
+ tx.rollback();
+
+ assertStoreEmpty();
+ }
+
+ public void testPutXARollback() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.rollback(xid);
+
+ assertStoreEmpty();
+ }
+
+ public void testRemoveTransactionalRollback() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.remove(tx, id);
+
+ tx.rollback();
+
+ assertContainsPair(id, bytes, 1);
+ }
+
+ public void testRemoveXARollback() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.remove(null, id);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.rollback(xid);
+
+ assertContainsPair(id, bytes, 1);
+ }
+
+
+ public void testPutAndRemoveMultipleTransactionalCommit() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ byte[] bytes3 = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
+
+ byte[] bytes4 = new byte[] { 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
+
+ long id1 = 1;
+
+ long id2 = 2;
+
+ long id3 = 3;
+
+ long id4 = 4;
+
+ int offset = 0;
+
+ database.put(null, id1, bytes1, offset, bytes1.length);
+
+ database.put(null, id2, bytes2, offset, bytes2.length);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id3, bytes3, offset, bytes3.length);
+
+ database.put(tx, id4, bytes4, offset, bytes4.length);
+
+ database.remove(tx, id1);
+
+ database.remove(tx, id2);
+
+ tx.commit();
+
+ assertContainsPair(id3, bytes3, 2);
+
+ assertContainsPair(id4, bytes4, 2);
+ }
+
+ public void testPutAndRemoveMultipleXACommit() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ byte[] bytes3 = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
+
+ byte[] bytes4 = new byte[] { 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
+
+ long id1 = 1;
+
+ long id2 = 2;
+
+ long id3 = 3;
+
+ long id4 = 4;
+
+ int offset = 0;
+
+ database.put(null, id1, bytes1, offset, bytes1.length);
+
+ database.put(null, id2, bytes2, offset, bytes2.length);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id3, bytes3, offset, bytes3.length);
+
+ database.put(null, id4, bytes4, offset, bytes4.length);
+
+ database.remove(null, id1);
+
+ database.remove(null, id2);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.commit(xid);
+
+ assertContainsPair(id3, bytes3, 2);
+
+ assertContainsPair(id4, bytes4, 2);
+ }
+
+ public void testPutAndRemoveMultipleXAWithRestart() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ byte[] bytes3 = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
+
+ byte[] bytes4 = new byte[] { 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
+
+ long id1 = 1;
+
+ long id2 = 2;
+
+ long id3 = 3;
+
+ long id4 = 4;
+
+ int offset = 0;
+
+ database.put(null, id1, bytes1, offset, bytes1.length);
+
+ database.put(null, id2, bytes2, offset, bytes2.length);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id3, bytes3, offset, bytes3.length);
+
+ database.put(null, id4, bytes4, offset, bytes4.length);
+
+ database.remove(null, id1);
+
+ database.remove(null, id2);
+
+ env.endWork(xid, false);
+
+ // Now restart
+
+ database.close();
+
+ env.stop();
+
+ env.start();
+
+ database = env.getDatabase(DB_NAME);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+ }
+
+ public void testPutAndRemoveMultipleTransactionalRollback() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ byte[] bytes3 = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
+
+ byte[] bytes4 = new byte[] { 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
+
+ long id1 = 1;
+
+ long id2 = 2;
+
+ long id3 = 3;
+
+ long id4 = 4;
+
+ int offset = 0;
+
+ database.put(null, id1, bytes1, offset, bytes1.length);
+
+ database.put(null, id2, bytes2, offset, bytes2.length);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id3, bytes3, offset, bytes3.length);
+
+ database.put(tx, id4, bytes4, offset, bytes4.length);
+
+ database.remove(tx, id1);
+
+ database.remove(tx, id2);
+
+ tx.rollback();
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+ }
+
+ public void testPutAndRemoveMultipleXARollback() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ byte[] bytes3 = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
+
+ byte[] bytes4 = new byte[] { 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
+
+ long id1 = 1;
+
+ long id2 = 2;
+
+ long id3 = 3;
+
+ long id4 = 4;
+
+ int offset = 0;
+
+ database.put(null, id1, bytes1, offset, bytes1.length);
+
+ database.put(null, id2, bytes2, offset, bytes2.length);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id3, bytes3, offset, bytes3.length);
+
+ database.put(null, id4, bytes4, offset, bytes4.length);
+
+ database.remove(null, id1);
+
+ database.remove(null, id2);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.rollback(xid);
+
+ assertContainsPair(id1, bytes1, 2);
+
+ assertContainsPair(id2, bytes2, 2);
+ }
+
+ public void testOverwiteNonTransactional() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes1, offset, bytes1.length);
+
+ assertContainsPair(id, bytes1, 1);
+
+ database.put(null, id, bytes2, offset, bytes1.length);
+
+ assertContainsPair(id, bytes2, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testOverwiteTransactionalCommit() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id, bytes1, offset, bytes1.length);
+
+ database.put(tx, id, bytes2, offset, bytes1.length);
+
+ tx.commit();
+
+ assertContainsPair(id, bytes2, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testOverwiteXACommit() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id, bytes1, offset, bytes1.length);
+
+ database.put(null, id, bytes2, offset, bytes1.length);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.commit(xid);
+
+ assertContainsPair(id, bytes2, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testOverwiteTransactionalRollback() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id, bytes1, offset, bytes1.length);
+
+ database.put(tx, id, bytes2, offset, bytes1.length);
+
+ tx.rollback();
+
+ assertStoreEmpty();
+ }
+
+ public void testOverwiteXARollback() throws Exception
+ {
+ byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ database.put(null, id, bytes1, offset, bytes1.length);
+
+ database.put(null, id, bytes2, offset, bytes1.length);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.rollback(xid);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutAndRemovePartialNonTransactional() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 20, 21, 22, 23 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ database.put(null, id, bytes, offset, bytes.length);
+
+ assertContainsPair(id, bytes, 1);
+
+ database.put(null, id, bytes2, 10, bytes2.length);
+
+ byte[] bytes3 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes3, 1);
+
+ database.put(null, id, bytes2, 3, bytes2.length);
+
+ byte[] bytes4 = new byte[] { 1, 2, 3, 20, 21, 22, 23, 8, 9, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes4, 1);
+
+ byte[] bytes5 = new byte[0];
+
+ //blank out 4 bytes
+ database.put(null, id, bytes5, 5, 4);
+
+ byte[] bytes6 = new byte[] { 1, 2, 3, 20, 21, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes6, 1);
+
+
+ database.put(null, id, new byte[0], 0, 4);
+
+ byte[] bytes7 = new byte[] { 21, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes7, 1);
+
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testPutAndRemovePartialTransactional() throws Exception
+ {
+ byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+ byte[] bytes2 = new byte[] { 20, 21, 22, 23 };
+
+ long id = 1;
+
+ int offset = 0;
+
+ BDBJETransaction tx = env.createTransaction();
+
+ database.put(tx, id, bytes, offset, bytes.length);
+
+ tx.commit();
+
+ assertContainsPair(id, bytes, 1);
+
+ tx = env.createTransaction();
+
+ database.put(tx, id, bytes2, 10, bytes2.length);
+
+ tx.commit();
+
+ byte[] bytes3 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes3, 1);
+
+ tx = env.createTransaction();
+
+ database.put(tx, id, bytes2, 3, bytes2.length);
+
+ tx.commit();
+
+ byte[] bytes4 = new byte[] { 1, 2, 3, 20, 21, 22, 23, 8, 9, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes4, 1);
+
+ byte[] bytes5 = new byte[0];
+
+ tx = env.createTransaction();
+
+ //blank out 4 bytes
+ database.put(tx, id, bytes5, 5, 4);
+
+ tx.commit();
+
+ byte[] bytes6 = new byte[] { 1, 2, 3, 20, 21, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes6, 1);
+
+ database.put(null, id, new byte[0], 0, 4);
+
+ byte[] bytes7 = new byte[] { 21, 10, 20, 21, 22, 23 };
+
+ assertContainsPair(id, bytes7, 1);
+
+ database.remove(null, 1);
+
+ assertStoreEmpty();
+ }
+
+ public void testSetAndGetEnvironment() throws Exception
+ {
+ BDBJEEnvironment bdb = createEnvironment();
+
+ final String path = "/home/tim/test-path123";
+
+ createDir(path);
+
+ assertNull(bdb.getEnvironmentPath());
+
+ bdb.setEnvironmentPath(path);
+
+ assertEquals(path, bdb.getEnvironmentPath());
+
+ bdb.start();
+
+ try
+ {
+ bdb.setEnvironmentPath("blah");
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ assertEquals(path, bdb.getEnvironmentPath());
+
+ bdb.stop();
+
+ final String path2 = "test-path123651";
+
+ bdb.setEnvironmentPath(path2);
+
+ assertEquals(path2, bdb.getEnvironmentPath());
+ }
+
+
+ public void testSetAndGetTransacted() throws Exception
+ {
+ BDBJEEnvironment bdb = createEnvironment();
+
+ final String path = "/home/tim/test-path123";
+
+ createDir(path);
+
+ bdb.setEnvironmentPath(path);
+
+ bdb.setTransacted(false);
+
+ assertFalse(bdb.isTransacted());
+
+ bdb.setTransacted(true);
+
+ assertTrue(bdb.isTransacted());
+
+ bdb.start();
+
+ try
+ {
+ bdb.setTransacted(true);
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ assertTrue(bdb.isTransacted());
+
+ bdb.stop();
+
+ bdb.setTransacted(false);
+
+ assertFalse(bdb.isTransacted());
+ }
+
+ public void testSetAndGetSyncOS() throws Exception
+ {
+ BDBJEEnvironment bdb = createEnvironment();
+
+ final String path = "/home/tim/test-path123";
+
+ createDir(path);
+
+ bdb.setEnvironmentPath(path);
+
+ assertFalse(bdb.isSyncOS());
+
+ bdb.setSyncOS(true);
+
+ assertTrue(bdb.isSyncOS());
+
+ bdb.start();
+
+ try
+ {
+ bdb.setSyncOS(true);
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ assertTrue(bdb.isSyncOS());
+
+ bdb.stop();
+
+ bdb.setSyncOS(false);
+
+ assertFalse(bdb.isSyncOS());
+ }
+
+ public void testSetAndGetSyncVM() throws Exception
+ {
+ BDBJEEnvironment bdb = createEnvironment();
+
+ final String path = "/home/tim/test-path123";
+
+ bdb.setEnvironmentPath(path);
+
+ createDir(path);
+
+ assertFalse(bdb.isSyncVM());
+
+ bdb.setSyncVM(true);
+
+ assertTrue(bdb.isSyncVM());
+
+ bdb.start();
+
+ try
+ {
+ bdb.setSyncVM(true);
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ assertTrue(bdb.isSyncVM());
+
+ bdb.stop();
+
+ bdb.setSyncVM(false);
+
+ assertFalse(bdb.isSyncVM());
+ }
+
+ public void testSetAndGetMemoryCacheSize() throws Exception
+ {
+ BDBJEEnvironment bdb = createEnvironment();
+
+ final String path = "/home/tim/test-path123";
+
+ createDir(path);
+
+ bdb.setEnvironmentPath(path);
+
+ assertEquals(-1, bdb.getMemoryCacheSize());
+
+ final long size = 16251762;
+
+ bdb.setMemoryCacheSize(size);
+
+ assertEquals(size, bdb.getMemoryCacheSize());
+
+ bdb.start();
+
+ try
+ {
+ bdb.setMemoryCacheSize(1897291289);
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ assertEquals(size, bdb.getMemoryCacheSize());
+
+ bdb.stop();
+
+ final long size2 = 1625534783;
+
+ bdb.setMemoryCacheSize(size2);
+
+ assertEquals(size2, bdb.getMemoryCacheSize());
+ }
+
+
+ public void testStartAndStop() throws Exception
+ {
+ BDBJEEnvironment bdb = createEnvironment();
+
+ try
+ {
+ bdb.start();
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ final String path = "/home/tim/test-path123";
+
+ createDir(path);
+
+ bdb.setEnvironmentPath(path);
+
+ bdb.start();
+
+ try
+ {
+ bdb.start();
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ bdb.stop();
+
+ try
+ {
+ bdb.stop();
+
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+ }
+
+ public void testWrongOrderCommit() throws Exception
+ {
+ testXAWrongOrder(true);
+ }
+
+ public void testWrongOrderRollback() throws Exception
+ {
+ testXAWrongOrder(false);
+ }
+
+ public void testXAWrongXidCommit() throws Exception
+ {
+ testXAWrongXid(true);
+ }
+
+ public void testXAWrongXidRollback() throws Exception
+ {
+ testXAWrongXid(false);
+ }
+
+ private void testXAWrongXid(boolean commit) throws Exception
+ {
+ Xid xid = generateXid();
+
+ env.startWork(xid);
+
+ Xid xid2 = generateXid();
+
+ try
+ {
+ env.endWork(xid2, false);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ //do some work
+
+ database.put(null, 23, new byte[10], 0, 10);
+
+ env.endWork(xid, false);
+
+ try
+ {
+ env.prepare(xid2);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ env.prepare(xid);
+
+ if (commit)
+ {
+ try
+ {
+ env.commit(xid2);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+ env.commit(xid);
+ }
+ else
+ {
+ try
+ {
+ env.rollback(xid2);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+ env.rollback(xid);
+ }
+ }
+
+ private void testXAWrongOrder(boolean commit) throws Exception
+ {
+ Xid xid = generateXid();
+
+ try
+ {
+ env.endWork(xid, false);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.prepare(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.commit(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.rollback(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ env.startWork(xid);
+
+ //do some work
+
+ database.put(null, 23, new byte[10], 0, 10);
+
+ try
+ {
+ env.startWork(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.prepare(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.commit(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.rollback(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ env.endWork(xid, false);
+
+ try
+ {
+ env.startWork(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.endWork(xid, false);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.commit(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.rollback(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ env.prepare(xid);
+
+ try
+ {
+ env.startWork(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.endWork(xid, false);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ if (commit)
+ {
+ env.commit(xid);
+ }
+ else
+ {
+ env.rollback(xid);
+ }
+
+ try
+ {
+ env.endWork(xid, false);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.prepare(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.commit(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ try
+ {
+ env.rollback(xid);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ env.startWork(xid);
+
+ database.put(null, 23, new byte[10], 0, 10);
+
+ env.endWork(xid, false);
+
+ env.prepare(xid);
+
+ env.rollback(xid);
+
+ }
+
+ // Private -------------------------------------------------------------------------------------
+
+ private void assertContainsPair(long id, byte[] bytes, long size) throws Exception
+ {
+ byte[] b = database.get(id);
+
+ assertNotNull(b);
+
+ assertByteArraysEquivalent(bytes, b);
+
+ assertEquals(size, database.size());
+ }
+
+ private void assertStoreEmpty() throws Exception
+ {
+ assertEquals(0, database.size());
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEPersistenceManagerTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEPersistenceManagerTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBJEPersistenceManagerTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,786 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.bdbje.test.unit;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.transaction.xa.Xid;
+
+import org.jboss.messaging.newcore.impl.MessageImpl;
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEDatabase;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEPersistenceManager;
+import org.jboss.messaging.newcore.impl.bdbje.test.unit.fakes.FakeBDBJEEnvironment;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A BDBJEPersistenceManagerTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class BDBJEPersistenceManagerTest extends UnitTestCase
+{
+ protected static final String ENV_DIR = "test-env";
+
+ protected BDBJEPersistenceManager pm;
+
+ protected BDBJEEnvironment bdb;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ bdb = new FakeBDBJEEnvironment();
+
+ pm = new BDBJEPersistenceManager(bdb, ENV_DIR);
+
+ pm.start();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ pm.stop();
+ }
+
+ // The tests ----------------------------------------------------------------
+
+ public void testAddMessage() throws Exception
+ {
+ Queue queue = new QueueImpl(67);
+
+ Message m = createMessageWithRefs(1, queue);
+
+ pm.addMessage(m);
+
+ assertMessageInStore(m, queue);
+ }
+
+ public void testDeleteReference() throws Exception
+ {
+ Queue queue = new QueueImpl(67);
+
+ Message m = createMessageWithRefs(1, queue);
+
+ List<MessageReference> refs = new ArrayList<MessageReference>(m.getReferences());
+
+
+ pm.addMessage(m);
+
+ assertMessageInStore(m, queue);
+
+
+ pm.deleteReference(refs.get(2));
+
+ assertMessageInStore(m, queue);
+
+ assertEquals(3, m.getReferences().size());
+
+ assertTrue(m.getReferences().contains(refs.get(0)));
+ assertTrue(m.getReferences().contains(refs.get(1)));
+ assertTrue(m.getReferences().contains(refs.get(3)));
+
+
+ pm.deleteReference(refs.get(1));
+
+ assertMessageInStore(m, queue);
+
+ assertEquals(2, m.getReferences().size());
+
+ assertTrue(m.getReferences().contains(refs.get(0)));
+ assertTrue(m.getReferences().contains(refs.get(3)));
+
+
+
+ pm.deleteReference(refs.get(3));
+
+ assertMessageInStore(m, queue);
+
+ assertEquals(1, m.getReferences().size());
+
+ assertTrue(m.getReferences().contains(refs.get(0)));
+
+
+ pm.deleteReference(refs.get(0));
+
+ assertMessageNotInStore(m);
+
+ assertStoreEmpty();
+ }
+
+ public void testCommitTransaction() throws Exception
+ {
+ List<Message> msgs = new ArrayList<Message>();
+
+ Queue queue = new QueueImpl(67);
+
+ Message m1 = createMessageWithRefs(1, queue);
+ List<MessageReference> m1Refs = new ArrayList<MessageReference>(m1.getReferences());
+
+ msgs.add(m1);
+
+ Message m2 = createMessageWithRefs(2, queue);
+
+ msgs.add(m2);
+
+ Message m3 = createMessageWithRefs(3, queue);
+ List<MessageReference> m3Refs = new ArrayList<MessageReference>(m3.getReferences());
+
+ msgs.add(m3);
+
+ pm.commitTransaction(msgs, null);
+
+ assertMessageInStore(m1, queue);
+
+ assertMessageInStore(m2, queue);
+
+ assertMessageInStore(m3, queue);
+
+
+ //Add a couple more
+
+ List<Message> msgsMore = new ArrayList<Message>();
+
+ Message m4 = createMessageWithRefs(4, queue);
+ msgsMore.add(m4);
+
+ Message m5 = createMessageWithRefs(5, queue);
+ msgsMore.add(m5);
+
+ //Delete some refs
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ refsToRemove.add(m1.getReferences().get(0));
+ refsToRemove.add(m1.getReferences().get(3));
+
+ refsToRemove.add(m2.getReferences().get(0));
+ refsToRemove.add(m2.getReferences().get(1));
+ refsToRemove.add(m2.getReferences().get(2));
+ refsToRemove.add(m2.getReferences().get(3));
+
+ refsToRemove.add(m3.getReferences().get(2));
+
+ pm.commitTransaction(msgsMore, refsToRemove);
+
+ assertMessageInStore(m1, queue);
+ assertEquals(2, m1.getReferences().size());
+ assertTrue(m1.getReferences().contains(m1Refs.get(1)));
+ assertTrue(m1.getReferences().contains(m1Refs.get(2)));
+
+ assertMessageNotInStore(m2);
+
+ assertMessageInStore(m3, queue);
+ assertEquals(3, m3.getReferences().size());
+ assertTrue(m3.getReferences().contains(m3Refs.get(0)));
+ assertTrue(m3.getReferences().contains(m3Refs.get(1)));
+ assertTrue(m3.getReferences().contains(m3Refs.get(3)));
+
+ assertMessageInStore(m4, queue);
+ assertEquals(4, m4.getReferences().size());
+
+ assertMessageInStore(m5, queue);
+ assertEquals(4, m5.getReferences().size());
+
+ //Delete the rest
+ refsToRemove.clear();
+ refsToRemove.addAll(m1.getReferences());
+ refsToRemove.addAll(m3.getReferences());
+ refsToRemove.addAll(m4.getReferences());
+ refsToRemove.addAll(m5.getReferences());
+
+ pm.commitTransaction(null, refsToRemove);
+
+ assertMessageNotInStore(m1);
+ assertMessageNotInStore(m2);
+ assertMessageNotInStore(m4);
+ assertMessageNotInStore(m5);
+ assertMessageNotInStore(m5);
+
+ //try with nulls
+ pm.commitTransaction(null, null);
+
+ }
+
+ public void testPrepareAndCommitTransaction() throws Exception
+ {
+ List<Message> msgs = new ArrayList<Message>();
+
+ Queue queue = new QueueImpl(67);
+
+ Message m1 = createMessageWithRefs(1, queue);
+ List<MessageReference> m1Refs = new ArrayList<MessageReference>(m1.getReferences());
+
+ msgs.add(m1);
+
+ Message m2 = createMessageWithRefs(2, queue);
+
+ msgs.add(m2);
+
+ Message m3 = createMessageWithRefs(3, queue);
+ List<MessageReference> m3Refs = new ArrayList<MessageReference>(m3.getReferences());
+
+ msgs.add(m3);
+
+ pm.commitTransaction(msgs, null);
+
+ assertMessageInStore(m1, queue);
+
+ assertMessageInStore(m2, queue);
+
+ assertMessageInStore(m3, queue);
+
+
+ //Add a couple more
+
+ List<Message> msgsMore = new ArrayList<Message>();
+
+ Message m4 = createMessageWithRefs(4, queue);
+ msgsMore.add(m4);
+
+ Message m5 = createMessageWithRefs(5, queue);
+
+ msgsMore.add(m5);
+
+ //Delete some refs
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ refsToRemove.add(m1.getReferences().get(0));
+ refsToRemove.add(m1.getReferences().get(3));
+
+ refsToRemove.add(m2.getReferences().get(0));
+ refsToRemove.add(m2.getReferences().get(1));
+ refsToRemove.add(m2.getReferences().get(2));
+ refsToRemove.add(m2.getReferences().get(3));
+
+ refsToRemove.add(m3.getReferences().get(2));
+
+ Xid xid = generateXid();
+
+ pm.prepareTransaction(xid, msgsMore, refsToRemove);
+
+ pm.commitPreparedTransaction(xid);
+
+ assertMessageInStore(m1, queue);
+ assertEquals(2, m1.getReferences().size());
+ assertTrue(m1.getReferences().contains(m1Refs.get(1)));
+ assertTrue(m1.getReferences().contains(m1Refs.get(2)));
+
+ assertMessageNotInStore(m2);
+
+ assertMessageInStore(m3, queue);
+ assertEquals(3, m3.getReferences().size());
+ assertTrue(m3.getReferences().contains(m3Refs.get(0)));
+ assertTrue(m3.getReferences().contains(m3Refs.get(1)));
+ assertTrue(m3.getReferences().contains(m3Refs.get(3)));
+
+ assertMessageInStore(m4, queue);
+ assertEquals(4, m4.getReferences().size());
+
+ assertMessageInStore(m5, queue);
+ assertEquals(4, m5.getReferences().size());
+
+ //Delete the rest
+ refsToRemove.clear();
+ refsToRemove.addAll(m1.getReferences());
+ refsToRemove.addAll(m3.getReferences());
+ refsToRemove.addAll(m4.getReferences());
+ refsToRemove.addAll(m5.getReferences());
+
+ xid = generateXid();
+
+ pm.prepareTransaction(xid, null, refsToRemove);
+
+ pm.commitPreparedTransaction(xid);
+
+ assertMessageNotInStore(m1);
+ assertMessageNotInStore(m2);
+ assertMessageNotInStore(m4);
+ assertMessageNotInStore(m5);
+ assertMessageNotInStore(m5);
+
+ //try with nulls
+ xid = generateXid();
+ pm.prepareTransaction(xid, null, null);
+ pm.commitPreparedTransaction(xid);
+
+ }
+
+ public void testPrepareAndUnprepareTransaction() throws Exception
+ {
+ List<Message> msgs = new ArrayList<Message>();
+
+ Queue queue = new QueueImpl(67);
+
+ Message m1 = createMessageWithRefs(1, queue);
+
+ msgs.add(m1);
+
+ Message m2 = createMessageWithRefs(2, queue);
+
+ msgs.add(m2);
+
+ Message m3 = createMessageWithRefs(3, queue);
+
+ msgs.add(m3);
+
+ pm.commitTransaction(msgs, null);
+
+ assertMessageInStore(m1, queue);
+
+ assertMessageInStore(m2, queue);
+
+ assertMessageInStore(m3, queue);
+
+
+ //Add a couple more
+
+ List<Message> msgsMore = new ArrayList<Message>();
+
+ Message m4 = createMessageWithRefs(4, queue);
+ msgsMore.add(m4);
+
+ Message m5 = createMessageWithRefs(5, queue);
+ msgsMore.add(m5);
+
+ //Delete some refs
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ refsToRemove.add(m1.getReferences().get(0));
+ refsToRemove.add(m1.getReferences().get(3));
+
+ refsToRemove.add(m2.getReferences().get(0));
+ refsToRemove.add(m2.getReferences().get(1));
+ refsToRemove.add(m2.getReferences().get(2));
+ refsToRemove.add(m2.getReferences().get(3));
+
+ refsToRemove.add(m3.getReferences().get(2));
+
+ Xid xid = generateXid();
+
+ pm.prepareTransaction(xid, msgsMore, refsToRemove);
+
+ pm.unprepareTransaction(xid, msgsMore, refsToRemove);
+
+ assertNumMessagesInStore(3);
+ }
+
+ public void testUpdateDeliveryCount() throws Exception
+ {
+ Queue queue = new QueueImpl(67);
+
+ Message m1 = createMessageWithRefs(1, queue);
+
+ assertEquals(0, m1.getReferences().get(0).getDeliveryCount());
+ assertEquals(0, m1.getReferences().get(1).getDeliveryCount());
+ assertEquals(0, m1.getReferences().get(2).getDeliveryCount());
+ assertEquals(0, m1.getReferences().get(3).getDeliveryCount());
+
+ pm.addMessage(m1);
+
+ final int delCount = 77;
+ m1.getReferences().get(1).setDeliveryCount(delCount);
+ pm.updateDeliveryCount(queue, m1.getReferences().get(1));
+
+ final int delCount2 = 423;
+
+ m1.getReferences().get(3).setDeliveryCount(delCount2);
+ pm.updateDeliveryCount(queue, m1.getReferences().get(3));
+
+ assertMessageInStore(m1, queue);
+ }
+
+ public void testRefsWithDifferentQueues() throws Exception
+ {
+ final int numQueues = 10;
+
+ List<Message> msgs = new ArrayList<Message>();
+
+ for (int i = 0; i < numQueues; i++)
+ {
+ Queue queue = new QueueImpl(i);
+
+ MessageReference ref = generateReference(queue, i);
+
+ msgs.add(ref.getMessage());
+
+ pm.addMessage(ref.getMessage());
+
+ assertEquals(queue, ref.getQueue());
+ }
+
+ for (Message msg: msgs)
+ {
+ assertMessageInStore(msg, msg.getReferences().get(0).getQueue());
+ }
+ }
+
+ public void testLoadQueues() throws Exception
+ {
+ Map<Long, Queue> queues = new HashMap<Long, Queue>();
+
+ final int numQueues = 10;
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numQueues; i++)
+ {
+ Queue queue = new QueueImpl(i);
+
+ queues.put(queue.getID(), queue);
+ }
+
+ List<Message> msgs = new ArrayList<Message>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ Message msg = this.generateMessage(i);
+
+ msgs.add(msg);
+
+ for (long j = 0; j < numQueues; j++)
+ {
+ Queue queue = queues.get(j);
+
+ msg.createReference(queue);
+ }
+
+ pm.addMessage(msg);
+ }
+
+
+ pm.loadQueues(queues);
+
+ for (Queue queue: queues.values())
+ {
+ assertEquals(numMessages, queue.getMessageCount());
+
+ List<MessageReference> refs = queue.list(null);
+
+ int i = 0;
+ for (MessageReference ref: refs)
+ {
+ this.assertEquivalent(msgs.get(i++), ref.getMessage());
+ }
+ }
+ }
+
+ public void testGetInDoubtXids() throws Exception
+ {
+ Queue queue = new QueueImpl(12);
+
+ Message message1 = createMessageWithRefs(1, queue);
+
+ List<Message> msgs = new ArrayList<Message>();
+
+ msgs.add(message1);
+
+ Xid xid1 = generateXid();
+
+ pm.prepareTransaction(xid1, msgs, null);
+
+ pm.setInRecoveryMode(true);
+
+ List<Xid> xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(1, xids.size());
+
+ assertEquals(xid1, xids.get(0));
+
+
+
+ Message message2 = createMessageWithRefs(2, queue);
+
+ msgs.clear();
+
+ msgs.add(message2);
+
+ Xid xid2 = generateXid();
+
+ pm.prepareTransaction(xid2, msgs, null);
+
+ xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(2, xids.size());
+
+ assertTrue(xids.contains(xid1));
+
+ assertTrue(xids.contains(xid2));
+
+
+ pm.commitPreparedTransaction(xid1);
+
+ pm.commitPreparedTransaction(xid2);
+
+ xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(0, xids.size());
+ }
+
+ public void testGetInDoubtXidsWithRestart() throws Exception
+ {
+ Queue queue = new QueueImpl(12);
+
+ Message message1 = createMessageWithRefs(1, queue);
+
+ List<Message> msgs = new ArrayList<Message>();
+
+ msgs.add(message1);
+
+ Xid xid1 = generateXid();
+
+ pm.prepareTransaction(xid1, msgs, null);
+
+ pm.setInRecoveryMode(true);
+
+ List<Xid> xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(1, xids.size());
+
+ assertEquals(xid1, xids.get(0));
+
+
+
+ Message message2 = createMessageWithRefs(2, queue);
+
+ msgs.clear();
+
+ msgs.add(message2);
+
+ Xid xid2 = generateXid();
+
+ pm.prepareTransaction(xid2, msgs, null);
+
+ xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(2, xids.size());
+
+ assertTrue(xids.contains(xid1));
+
+ assertTrue(xids.contains(xid2));
+
+ pm.stop();
+
+ pm.start();
+
+ pm.setInRecoveryMode(true);
+
+ xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(2, xids.size());
+
+ assertTrue(xids.contains(xid1));
+
+ assertTrue(xids.contains(xid2));
+
+
+ pm.commitPreparedTransaction(xid1);
+
+ pm.commitPreparedTransaction(xid2);
+
+ xids = pm.getInDoubtXids();
+
+ assertNotNull(xids);
+
+ assertEquals(0, xids.size());
+ }
+
+ public void testSetGetRecoveryMode() throws Exception
+ {
+ assertFalse(pm.isInRecoveryMode());
+
+ try
+ {
+ pm.getInDoubtXids();
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+
+ pm.setInRecoveryMode(true);
+
+ assertTrue(pm.isInRecoveryMode());
+
+ pm.getInDoubtXids();
+
+ pm.setInRecoveryMode(false);
+
+ assertFalse(pm.isInRecoveryMode());
+ }
+
+ // Private --------------------------------------------------------------------
+
+ private Message extractMessage(Map<Long, Queue> queues, long id, byte[] msgBytes, byte[] refBytes) throws Exception
+ {
+ ByteBuffer buffer = ByteBuffer.wrap(msgBytes);
+
+ int type = buffer.getInt();
+
+ long expiration = buffer.getLong();
+
+ long timestamp = buffer.getLong();
+
+ byte priority = buffer.get();
+
+ int headerSize = buffer.getInt();
+
+ byte[] headers = new byte[headerSize];
+
+ buffer.get(headers);
+
+ int payloadSize = buffer.getInt();
+
+ byte[] payload = null;
+
+ if (payloadSize != 0)
+ {
+ payload = new byte[payloadSize];
+
+ buffer.get(payload);
+ }
+
+ Message message = new MessageImpl(id, type, true, expiration, timestamp, priority,
+ headers, payload);
+
+ buffer = ByteBuffer.wrap(refBytes);
+
+ while (buffer.hasRemaining())
+ {
+ long queueID = buffer.getLong();
+
+ int deliveryCount = buffer.getInt();
+
+ long scheduledDeliveryTime = buffer.getLong();
+
+ MessageReference reference = message.createReference(queues.get(queueID));
+
+ reference.setDeliveryCount(deliveryCount);
+
+ reference.setScheduledDeliveryTime(scheduledDeliveryTime);
+ }
+
+ return message;
+ }
+
+ private void assertMessageInStore(Message m, Queue queue) throws Exception
+ {
+ BDBJEDatabase msgDB = bdb.getDatabase(BDBJEPersistenceManager.MESSAGE_DB_NAME);
+
+ BDBJEDatabase refDB = bdb.getDatabase(BDBJEPersistenceManager.REFERENCE_DB_NAME);
+
+ byte[] msgBytes = msgDB.get(m.getMessageID());
+
+ assertNotNull(msgBytes);
+
+ byte[] refBytes = refDB.get(m.getMessageID());
+
+ assertNotNull(refBytes);
+
+ Map<Long, Queue> queues = new HashMap<Long, Queue>();
+
+ queues.put(queue.getID(), queue);
+
+ Message m2 = extractMessage(queues, m.getMessageID(), msgBytes, refBytes);
+
+ assertEquivalent(m, m2);
+ }
+
+ private void assertNumMessagesInStore(int num) throws Exception
+ {
+ BDBJEDatabase msgDB = bdb.getDatabase(BDBJEPersistenceManager.MESSAGE_DB_NAME);
+
+ assertEquals(num, msgDB.size());
+ }
+
+ private void assertMessageNotInStore(Message m) throws Exception
+ {
+ BDBJEDatabase msgDB = bdb.getDatabase(BDBJEPersistenceManager.MESSAGE_DB_NAME);
+
+ BDBJEDatabase refDB = bdb.getDatabase(BDBJEPersistenceManager.REFERENCE_DB_NAME);
+
+
+ byte[] msgBytes = msgDB.get(m.getMessageID());
+
+ assertNull(msgBytes);
+
+ byte[] refBytes = refDB.get(m.getMessageID());
+
+ assertNull(refBytes);
+ }
+
+ private void assertStoreEmpty() throws Exception
+ {
+ BDBJEDatabase msgDB = bdb.getDatabase(BDBJEPersistenceManager.MESSAGE_DB_NAME);
+
+ BDBJEDatabase refDB = bdb.getDatabase(BDBJEPersistenceManager.REFERENCE_DB_NAME);
+
+ assertEquals(0, msgDB.size());
+
+ assertEquals(0, refDB.size());
+ }
+
+ private Message createMessageWithRefs(long id, Queue queue)
+ {
+ Message m = generateMessage(id);
+
+ m.createReference(queue);
+
+ m.createReference(queue);
+
+ m.createReference(queue);
+
+ m.createReference(queue);
+
+ return m;
+ }
+
+
+ // Inner classes ---------------------------------------------------------------
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBSpeedTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBSpeedTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/BDBSpeedTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,656 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.bdbje.test.unit;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.xa.Xid;
+
+import org.jboss.jms.tx.MessagingXid;
+import org.jboss.messaging.newcore.impl.MessageImpl;
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEPersistenceManager;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A BDBSpeedTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class BDBSpeedTest extends UnitTestCase
+{
+
+// public void testCommitMessage() throws Exception
+// {
+// String envPath = "/home/tim/test-env";
+//
+// File file = new File(envPath);
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// final int numMessages = 5000;
+//
+// final int numRefs = 10;
+//
+// BDBJEPersistenceManager2 bdb = new BDBJEPersistenceManager2(envPath);
+//
+// bdb.start();
+//
+// Queue queue = new QueueImpl(1);
+//
+// //List<Message> messages = new ArrayList<Message>();
+//
+// long start = System.currentTimeMillis();
+//
+// byte[] payload = new byte[1 * 1024];
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// Message message = new MessageImpl(i, 0, true, 0, System.currentTimeMillis(), (byte)4);
+//
+// for (int j = 0; j < numRefs; j++)
+// {
+// message.createReference(queue);
+//
+// message.setPayload(payload);
+// }
+//
+// //messages.add(message);
+//
+// bdb.commitMessage(message);
+// }
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Insert Rate: " + rate);
+//
+// }
+//
+// public void testCommitMessages() throws Exception
+// {
+// String envPath = "/home/tim/test-env";
+//
+// File file = new File(envPath);
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// final int numMessages = 5000;
+//
+// final int numRefs = 10;
+//
+// BDBJEPersistenceManager2 bdb = new BDBJEPersistenceManager2(envPath);
+//
+// bdb.start();
+//
+// Queue queue = new QueueImpl(1);
+//
+// List<Message> messages = new ArrayList<Message>();
+//
+// long start = System.currentTimeMillis();
+//
+// byte[] payload = new byte[1 * 1024];
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// Message message = new MessageImpl(i, 0, true, 0, System.currentTimeMillis(), (byte)4);
+//
+// for (int j = 0; j < numRefs; j++)
+// {
+// message.createReference(queue);
+//
+// message.setPayload(payload);
+// }
+//
+// messages.add(message);
+//
+// if (i % 100 == 0)
+// {
+// bdb.commitMessages(messages);
+//
+// messages.clear();
+// }
+// }
+// bdb.commitMessages(messages);
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Insert Rate: " + rate);
+//
+// }
+//
+// public void testDeleteReferences() throws Exception
+// {
+// String envPath = "/home/tim/test-env";
+//
+// File file = new File(envPath);
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// final int numMessages = 5000;
+//
+// final int numRefs = 10;
+//
+// BDBJEPersistenceManager2 bdb = new BDBJEPersistenceManager2(envPath);
+//
+// bdb.start();
+//
+// Queue queue = new QueueImpl(1);
+//
+// List<Message> messages = new ArrayList<Message>();
+//
+// byte[] payload = new byte[1 * 1024];
+//
+// List<MessageReference> refs = new ArrayList<MessageReference>();
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// Message message = new MessageImpl(i, 0, true, 0, System.currentTimeMillis(), (byte)4);
+//
+// for (int j = 0; j < numRefs; j++)
+// {
+// MessageReference ref = message.createReference(queue);
+//
+// message.setPayload(payload);
+//
+// refs.add(ref);
+// }
+//
+// messages.add(message);
+//
+// if (i % 100 == 0)
+// {
+// bdb.commitMessages(messages);
+//
+// messages.clear();
+// }
+// }
+// bdb.commitMessages(messages);
+//
+// long start = System.currentTimeMillis();
+//
+// //Now delete them
+//
+// bdb.deleteReferences(refs);
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Delete Rate: " + rate);
+//
+// }
+//
+// public void testDeleteReference() throws Exception
+// {
+// String envPath = "/home/tim/test-env";
+//
+// File file = new File(envPath);
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// final int numMessages = 5000;
+//
+// final int numRefs = 1;
+//
+// BDBJEPersistenceManager bdb = new BDBJEPersistenceManager(envPath);
+//
+// bdb.start();
+//
+// Queue queue = new QueueImpl(1);
+//
+// List<Message> messages = new ArrayList<Message>();
+//
+// byte[] payload = new byte[1 * 1024];
+//
+// List<MessageReference> refs = new ArrayList<MessageReference>();
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// Message message = new MessageImpl(i, 0, true, 0, System.currentTimeMillis(), (byte)4);
+//
+// for (int j = 0; j < numRefs; j++)
+// {
+// MessageReference ref = message.createReference(queue);
+//
+// message.setPayload(payload);
+//
+// refs.add(ref);
+// }
+//
+// messages.add(message);
+//
+// if (i % 100 == 0)
+// {
+// bdb.commitMessages(messages);
+//
+// messages.clear();
+// }
+// }
+// bdb.commitMessages(messages);
+//
+// System.out.println("Added them");
+//
+// long start = System.currentTimeMillis();
+//
+// //Now delete them
+//
+// for (MessageReference ref: refs)
+// {
+// bdb.deleteReference(ref);
+// }
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Delete Rate: " + rate);
+//
+// }
+//
+//
+// public void testPrepareMessages() throws Exception
+// {
+// String envPath = "/home/tim/test-env";
+//
+// File file = new File(envPath);
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// final int numMessages = 5000;
+//
+// final int numRefs = 10;
+//
+// BDBJEPersistenceManager2 bdb = new BDBJEPersistenceManager2(envPath);
+//
+// bdb.start();
+//
+// Queue queue = new QueueImpl(1);
+//
+// List<Message> messages = new ArrayList<Message>();
+//
+// long start = System.currentTimeMillis();
+//
+// byte[] payload = new byte[1 * 1024];
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// Message message = new MessageImpl(i, 0, true, 0, System.currentTimeMillis(), (byte)4);
+//
+// for (int j = 0; j < numRefs; j++)
+// {
+// message.createReference(queue);
+//
+// message.setPayload(payload);
+// }
+//
+// messages.add(message);
+//
+// if (i % 100 == 0)
+// {
+// Xid xid = this.generateXid();
+//
+// bdb.prepareMessages(xid, messages);
+//
+// bdb.commitPreparedMessages(xid);
+//
+// messages.clear();
+// }
+// }
+//
+// Xid xid = this.generateXid();
+//
+// bdb.prepareMessages(xid, messages);
+//
+// bdb.commitPreparedMessages(xid);
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Insert Rate: " + rate);
+//
+// }
+
+// /*
+// * Test with message and ref in separate databases
+// */
+// public void testMsgandRefsDifferentDBSNoXA() throws Exception
+// {
+// File file = new File("/home/tim/test-env");
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// EnvironmentConfig envConfig = new EnvironmentConfig();
+//
+// envConfig.setAllowCreate(true);
+//
+// envConfig.setTransactional(true);
+//
+//// envConfig.setTxnNoSync(true);
+////
+//// envConfig.setTxnWriteNoSync(true);
+//
+// Environment env1 = new Environment(file, envConfig);
+//
+// DatabaseConfig dbConfig1 = new DatabaseConfig();
+//
+// dbConfig1.setTransactional(true);
+//
+// dbConfig1.setAllowCreate(true);
+//
+// Database msgDB = env1.openDatabase(null, "message", dbConfig1);
+//
+// DatabaseConfig dbConfig2 = new DatabaseConfig();
+//
+// dbConfig2.setTransactional(true);
+//
+// dbConfig2.setAllowCreate(true);
+//
+// Database refDB = env1.openDatabase(null, "ref", dbConfig2);
+//
+//
+// DatabaseConfig dbConfig3 = new DatabaseConfig();
+//
+// dbConfig3.setTransactional(true);
+//
+// dbConfig3.setAllowCreate(true);
+//
+// Database txDB = env1.openDatabase(null, "tx", dbConfig3);
+//
+//
+//
+// final int numMessages = 5000;
+//
+// byte[] msgBytes = new byte[256];
+//
+// final int numRefs = 10;
+//
+// byte[] refBytes = new byte[numRefs * 20];
+//
+// byte[] txBytes = new byte[numRefs * 50];
+//
+//
+// long start = System.currentTimeMillis();
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// byte[] keyBytes = new byte[8];
+//
+// ByteBuffer buffer = ByteBuffer.wrap(keyBytes);
+//
+// buffer.putLong(i);
+//
+// DatabaseEntry key = new DatabaseEntry(keyBytes);
+//
+//
+// //Prepare refs
+//
+// DatabaseEntry refVal = new DatabaseEntry(refBytes);
+//
+// Transaction tx = env1.beginTransaction(null, null);
+//
+// refDB.put(tx, key, refVal);
+//
+// // Message
+//
+// DatabaseEntry msgVal = new DatabaseEntry(msgBytes);
+//
+// msgDB.put(tx, key, msgVal);
+//
+// //Write a tx record
+//
+// DatabaseEntry txVal = new DatabaseEntry(txBytes);
+//
+// txDB.put(tx, key, txVal);
+//
+// //Commit the prepare
+//
+// tx.commit();
+//
+// tx = env1.beginTransaction(null, null);
+//
+// //Now commit the refs
+//
+// refVal = new DatabaseEntry(refBytes);
+//
+// refDB.put(tx, key, refVal);
+//
+// //And delete the tx record
+//
+// txDB.delete(tx, key);
+//
+// tx.commit();
+// }
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Insert Rate: " + rate);
+//
+//
+// }
+//
+// public void testMsgandRefsDifferentDBSXA() throws Exception
+// {
+// File file = new File("/home/tim/test-env");
+//
+// deleteDirectory(file);
+//
+// file.mkdir();
+//
+// EnvironmentConfig envConfig = new EnvironmentConfig();
+//
+// envConfig.setAllowCreate(true);
+//
+// envConfig.setTransactional(true);
+//
+// XAEnvironment env1 = new XAEnvironment(file, envConfig);
+//
+// DatabaseConfig dbConfig1 = new DatabaseConfig();
+//
+// dbConfig1.setTransactional(true);
+//
+// dbConfig1.setAllowCreate(true);
+//
+// Database msgDB = env1.openDatabase(null, "message", dbConfig1);
+//
+// DatabaseConfig dbConfig2 = new DatabaseConfig();
+//
+// dbConfig2.setTransactional(true);
+//
+// dbConfig2.setAllowCreate(true);
+//
+// Database refDB = env1.openDatabase(null, "ref", dbConfig2);
+//
+//
+//
+// final int numMessages = 5000;
+//
+// byte[] msgBytes = new byte[256];
+//
+// final int numRefs = 10;
+//
+// byte[] refBytes = new byte[numRefs * 20];
+//
+// long start = System.currentTimeMillis();
+//
+// for (int i = 0; i < numMessages; i++)
+// {
+// Xid xid = generateXid();
+//
+// env1.start(xid, XAResource.TMNOFLAGS);
+//
+// byte[] keyBytes = new byte[8];
+//
+// ByteBuffer buffer = ByteBuffer.wrap(keyBytes);
+//
+// buffer.putLong(i);
+//
+// DatabaseEntry key = new DatabaseEntry(keyBytes);
+//
+// DatabaseEntry msgVal = new DatabaseEntry(msgBytes);
+//
+// Transaction tx = env1.beginTransaction(null, null);
+//
+// msgDB.put(null, key, msgVal);
+//
+// //Now the refs
+//
+// DatabaseEntry refVal = new DatabaseEntry(refBytes);
+//
+// refDB.put(null, key, refVal);
+//
+// env1.end(xid, XAResource.TMSUCCESS);
+//
+// env1.prepare(xid);
+//
+// env1.commit(xid, false);
+//
+// // tx.commit();
+// }
+//
+// long end = System.currentTimeMillis();
+//
+// double rate = 1000 * (double)numMessages / (end - start);
+//
+// System.out.println("Insert Rate: " + rate);
+//
+// start = System.currentTimeMillis();
+// }
+//
+// private Xid generateXid()
+// {
+// String id = java.util.UUID.randomUUID().toString();
+//
+// Xid xid = new MessagingXid("blah".getBytes(), 123, id.getBytes());
+//
+// return xid;
+// }
+//
+//
+//// This is very slow
+//// public void testMsgandRefsSameDBSNoXA() throws Exception
+//// {
+//// File file = new File("/home/tim/test-env");
+////
+//// deleteDirectory(file);
+////
+//// file.mkdir();
+////
+//// EnvironmentConfig envConfig = new EnvironmentConfig();
+////
+//// envConfig.setAllowCreate(true);
+////
+//// envConfig.setTransactional(true);
+////
+//// Environment env1 = new Environment(file, envConfig);
+////
+//// DatabaseConfig dbConfig1 = new DatabaseConfig();
+////
+//// dbConfig1.setTransactional(true);
+////
+//// dbConfig1.setAllowCreate(true);
+////
+//// Database msgDB = env1.openDatabase(null, "message", dbConfig1);
+////
+//// final int numMessages = 5000;
+////
+//// byte[] msgBytes = new byte[10 * 1024];
+////
+//// byte[] refBytes = new byte[24];
+////
+//// long start = System.currentTimeMillis();
+////
+//// for (int i = 0; i < numMessages; i++)
+//// {
+//// byte[] keyBytes = new byte[8];
+////
+//// ByteBuffer buffer = ByteBuffer.wrap(keyBytes);
+////
+//// buffer.putLong(i);
+////
+//// DatabaseEntry key = new DatabaseEntry(keyBytes);
+////
+//// DatabaseEntry msgVal = new DatabaseEntry(msgBytes);
+////
+//// Transaction tx = env1.beginTransaction(null, null);
+////
+//// msgDB.put(tx, key, msgVal);
+////
+//// //Now the refs
+////
+//// final int numRefs = 50;
+////
+//// for (int j = 0; j < numRefs; j++)
+//// {
+//// keyBytes = new byte[8];
+////
+//// buffer = ByteBuffer.wrap(keyBytes);
+////
+//// buffer.putLong(j);
+////
+//// key = new DatabaseEntry(keyBytes);
+////
+//// DatabaseEntry value = new DatabaseEntry();
+////
+//// value.setPartial(0, refBytes.length, true);
+////
+//// value.setData(refBytes);
+////
+//// msgDB.put(tx, key, value);
+//// }
+////
+//// tx.commit();
+////
+//// }
+////
+//// long end = System.currentTimeMillis();
+////
+//// double rate = 1000 * (double)numMessages / (end - start);
+////
+//// System.out.println("Rate: " + rate);
+//// }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/FakeBDBJEEnvironmentTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/FakeBDBJEEnvironmentTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/FakeBDBJEEnvironmentTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,25 @@
+package org.jboss.messaging.newcore.impl.bdbje.test.unit;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.test.unit.fakes.FakeBDBJEEnvironment;
+
+/**
+ *
+ * A FakeBDBJEEnvironmentTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class FakeBDBJEEnvironmentTest extends BDBJEEnvironmentTestBase
+{
+ protected BDBJEEnvironment createEnvironment() throws Exception
+ {
+ BDBJEEnvironment env = new FakeBDBJEEnvironment();
+
+ return env;
+ }
+
+ protected void createDir(String path)
+ {
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/fakes/FakeBDBJEEnvironment.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/fakes/FakeBDBJEEnvironment.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/bdbje/test/unit/fakes/FakeBDBJEEnvironment.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,501 @@
+package org.jboss.messaging.newcore.impl.bdbje.test.unit.fakes;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.transaction.xa.Xid;
+
+import org.jboss.messaging.newcore.impl.bdbje.BDBJECursor;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEDatabase;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJEEnvironment;
+import org.jboss.messaging.newcore.impl.bdbje.BDBJETransaction;
+import org.jboss.messaging.util.Pair;
+
+/**
+ *
+ * A FakeBDBJEEnvironment
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class FakeBDBJEEnvironment implements BDBJEEnvironment
+{
+ private String environmentPath;
+
+ private Map<String, FakeBDBJETransaction> transactions = new HashMap<String, FakeBDBJETransaction>();
+
+ private boolean transacted;
+
+ private boolean syncOS;
+
+ private boolean syncVM;
+
+ private long memoryCacheSize = -1;
+
+ private boolean started;
+
+ private Map<Thread, FakeBDBJETransaction> implicitTXs = new ConcurrentHashMap<Thread, FakeBDBJETransaction>();
+
+ private Map<String, BDBJEDatabase> databases = new HashMap<String, BDBJEDatabase>();
+
+ public boolean isSyncOS()
+ {
+ return syncOS;
+ }
+
+ public void setSyncOS(boolean sync)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set SyncOS when started");
+ }
+ syncOS = sync;
+ }
+
+ public boolean isSyncVM()
+ {
+ return syncVM;
+ }
+
+ public void setSyncVM(boolean sync)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set SyncVM when started");
+ }
+ syncVM = sync;
+ }
+
+ public boolean isTransacted()
+ {
+ return transacted;
+ }
+
+ public void setTransacted(boolean transacted)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set transacted when started");
+ }
+ this.transacted = transacted;
+ }
+
+ public long getMemoryCacheSize()
+ {
+ return memoryCacheSize;
+ }
+
+ public void setMemoryCacheSize(long size)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set memory cache size when started");
+ }
+ this.memoryCacheSize = size;
+ }
+
+ public void setEnvironmentPath(String environmentPath)
+ {
+ if (started)
+ {
+ throw new IllegalStateException("Cannot set environmentPath when started");
+ }
+ this.environmentPath = environmentPath;
+ }
+
+ public String getEnvironmentPath()
+ {
+ return environmentPath;
+ }
+
+ public void start() throws Exception
+ {
+ if (environmentPath == null)
+ {
+ throw new IllegalStateException("Must set environmentPath before starting");
+ }
+ if (started)
+ {
+ throw new IllegalStateException("Already started");
+ }
+ started = true;
+ }
+
+ public void stop() throws Exception
+ {
+ if (!started)
+ {
+ throw new IllegalStateException("Not started");
+ }
+ started = false;
+ }
+
+ public BDBJETransaction createTransaction() throws Exception
+ {
+ return createTransactionInternal(null);
+ }
+
+ public synchronized BDBJEDatabase getDatabase(String databaseName) throws Exception
+ {
+ BDBJEDatabase database = databases.get(databaseName);
+
+ if (database == null)
+ {
+ database = new FakeBDBJEDatabase();
+
+ databases.put(databaseName, database);
+ }
+
+ return database;
+ }
+
+ public List<Xid> getInDoubtXids() throws Exception
+ {
+ List<Xid> xids = new ArrayList<Xid>();
+
+ for (FakeBDBJETransaction tx: transactions.values())
+ {
+ if (tx.isPrepared())
+ {
+ xids.add(tx.getXid());
+ }
+ }
+
+ return xids;
+ }
+
+ public void startWork(Xid xid) throws Exception
+ {
+ if (implicitTXs.get(Thread.currentThread()) != null)
+ {
+ throw new IllegalStateException("Already implicit transaction");
+ }
+
+ implicitTXs.put(Thread.currentThread(), createTransactionInternal(xid));
+ }
+
+ public void endWork(Xid xid, boolean fail) throws Exception
+ {
+ FakeBDBJETransaction removed = implicitTXs.remove(Thread.currentThread());
+
+ if (removed == null)
+ {
+ throw new IllegalStateException("No implicit tx");
+ }
+ }
+
+ private FakeBDBJETransaction findTXForXid(Xid xid)
+ {
+ for (FakeBDBJETransaction tx: transactions.values())
+ {
+ if (xid.equals(tx.xid))
+ {
+ return tx;
+ }
+ }
+ return null;
+ }
+
+ public void prepare(Xid xid) throws Exception
+ {
+ FakeBDBJETransaction tx = findTXForXid(xid);
+
+ if (tx == null)
+ {
+ throw new IllegalStateException("Cannot find tx for xid " + xid);
+ }
+
+ if (implicitTXs.containsKey(Thread.currentThread()))
+ {
+ throw new IllegalStateException("Work not ended");
+ }
+
+ tx.prepare();
+ }
+
+ public void commit(Xid xid) throws Exception
+ {
+ FakeBDBJETransaction tx = findTXForXid(xid);
+
+ if (tx == null)
+ {
+ throw new IllegalStateException("Cannot find tx for xid " + xid);
+ }
+
+ if (implicitTXs.containsKey(Thread.currentThread()))
+ {
+ throw new IllegalStateException("Work not ended");
+ }
+
+ tx.commit();
+ }
+
+ public void rollback(Xid xid) throws Exception
+ {
+ FakeBDBJETransaction tx = findTXForXid(xid);
+
+ if (tx == null)
+ {
+ throw new IllegalStateException("Cannot find tx for xid " + xid);
+ }
+
+ if (implicitTXs.containsKey(Thread.currentThread()))
+ {
+ throw new IllegalStateException("Work not ended");
+ }
+
+ tx.rollback();
+ }
+
+ // Private -----------------------------------------------------------------------
+
+ private FakeBDBJETransaction createTransactionInternal(Xid xid) throws Exception
+ {
+ FakeBDBJETransaction tx = new FakeBDBJETransaction(xid);
+
+ transactions.put(tx.id, tx);
+
+ return tx;
+ }
+
+ // Inner classes ------------------------------------------------------------------
+
+ private class FakeBDBJETransaction implements BDBJETransaction
+ {
+ private String id = java.util.UUID.randomUUID().toString();
+
+ private Xid xid;
+
+ private List<Action> actions = new ArrayList<Action>();
+
+ private boolean prepared;
+
+ FakeBDBJETransaction(Xid xid)
+ {
+ this.xid = xid;
+ }
+
+ public void commit() throws Exception
+ {
+ for (Action action : actions)
+ {
+ if (action.put)
+ {
+ action.database.put(null, action.id, action.bytes, action.offset, action.length);
+ }
+ else
+ {
+ action.database.remove(null, action.id);
+ }
+ }
+
+ actions.clear();
+
+ transactions.remove(id);
+ }
+
+ public void prepare() throws Exception
+ {
+ prepared = true;
+ }
+
+ public void rollback() throws Exception
+ {
+ actions.clear();
+
+ transactions.remove(id);
+ }
+
+ public boolean isPrepared()
+ {
+ return prepared;
+ }
+
+ public Xid getXid()
+ {
+ return xid;
+ }
+
+ }
+
+ private class Action
+ {
+ public BDBJEDatabase database;
+
+ public boolean put;
+
+ public long id;
+
+ public byte[] bytes;
+
+ public int offset;
+
+ public int length;
+
+ public Action(BDBJEDatabase database, boolean put, long id, byte[] bytes, int offset, int length)
+ {
+ this.database = database;
+
+ this.put = put;
+
+ this.id = id;
+
+ this.bytes = bytes;
+
+ this.offset = offset;
+
+ this.length = length;
+ }
+ }
+
+ private class FakeBDBJEDatabase implements BDBJEDatabase
+ {
+ private Map<Long, byte[]> store = new LinkedHashMap<Long, byte[]>();
+
+ private AtomicInteger cursorCount = new AtomicInteger(0);
+
+ public void close() throws Exception
+ {
+ if (cursorCount.get() != 0)
+ {
+ throw new IllegalStateException("Cannot close. There are cursors open");
+ }
+ }
+
+ public BDBJECursor cursor() throws Exception
+ {
+ return new FakeBDBJECursor();
+ }
+
+ private BDBJETransaction getTx(BDBJETransaction tx)
+ {
+ if (tx == null)
+ {
+ tx = implicitTXs.get(Thread.currentThread());
+ }
+ return tx;
+ }
+
+ public void put(BDBJETransaction tx, long id, byte[] bytes, int offset,
+ int length) throws Exception
+ {
+ tx = getTx(tx);
+
+ if (tx == null)
+ {
+ if (offset == 0 && bytes.length == length)
+ {
+ store.put(id, bytes);
+ }
+ else
+ {
+ byte[] currentBytes = store.get(id);
+
+ if (offset == currentBytes.length)
+ {
+ byte[] newBytes = new byte[currentBytes.length + bytes.length];
+
+ ByteBuffer buffer = ByteBuffer.wrap(newBytes);
+
+ buffer.put(currentBytes);
+
+ buffer.put(bytes);
+
+ store.put(id, newBytes);
+ }
+ else if (offset < currentBytes.length)
+ {
+ if (offset + length > currentBytes.length)
+ {
+ throw new IllegalStateException("Invalid offset/length");
+ }
+
+ byte[] newBytes = new byte[currentBytes.length - (length - bytes.length)];
+
+ System.arraycopy(currentBytes, 0, newBytes, 0, offset);
+
+ System.arraycopy(bytes, 0, newBytes, offset, bytes.length);
+
+ System.arraycopy(currentBytes, offset + length, newBytes,
+ offset + bytes.length, currentBytes.length - (offset + length));
+
+ store.put(id, newBytes);
+ }
+ else
+ {
+ throw new IllegalStateException("Invalid offset " + offset);
+ }
+ }
+ }
+ else
+ {
+ FakeBDBJETransaction ftx = (FakeBDBJETransaction)tx;
+
+ ftx.actions.add(new Action(this, true, id, bytes, offset, length));
+ }
+
+ }
+
+ public void remove(BDBJETransaction tx, long id) throws Exception
+ {
+ tx = getTx(tx);
+
+ if (tx == null)
+ {
+ store.remove(id);
+ }
+ else
+ {
+ FakeBDBJETransaction ftx = (FakeBDBJETransaction)tx;
+
+ ftx.actions.add(new Action(this, false, id, null, -1, -1));
+ }
+ }
+
+ public byte[] get(long id) throws Exception
+ {
+ return store.get(id);
+ }
+
+ public long size() throws Exception
+ {
+ return store.size();
+ }
+
+ private class FakeBDBJECursor implements BDBJECursor
+ {
+ private Iterator<Map.Entry<Long,byte[]>> iterator = store.entrySet().iterator();
+
+ FakeBDBJECursor()
+ {
+ cursorCount.incrementAndGet();
+ }
+
+ public void close() throws Exception
+ {
+ cursorCount.decrementAndGet();
+ }
+
+ public Pair<Long, byte[]> getNext() throws Exception
+ {
+ if (iterator.hasNext())
+ {
+ Map.Entry<Long,byte[]> entry = iterator.next();
+
+ return new Pair<Long, byte[]>(entry.getKey(), entry.getValue());
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/concurrent/QueueTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/concurrent/QueueTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/concurrent/QueueTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,204 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.test.concurrent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.impl.test.unit.fakes.FakeConsumer;
+import org.jboss.messaging.newcore.intf.HandleStatus;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A concurrent QueueTest
+ *
+ * All the concurrent queue tests go in here
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class QueueTest extends UnitTestCase
+{
+ // The tests ----------------------------------------------------------------
+
+ /*
+ * Concurrent set consumer not busy, busy then, call deliver while messages are being added and consumed
+ */
+ public void testConcurrentAddsDeliver() throws Exception
+ {
+ Queue queue = new QueueImpl(1);
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ final long testTime = 5000;
+
+ Sender sender = new Sender(queue, testTime);
+
+ Toggler toggler = new Toggler(queue, consumer, testTime);
+
+ sender.start();
+
+ toggler.start();
+
+ sender.join();
+
+ toggler.join();
+
+ consumer.setStatusImmediate(HandleStatus.HANDLED);
+
+ queue.deliver();
+
+ if (sender.getException() != null)
+ {
+ throw sender.getException();
+ }
+
+ if (toggler.getException() != null)
+ {
+ throw toggler.getException();
+ }
+
+ assertRefListsIdenticalRefs(sender.getReferences(), consumer.getReferences());
+
+ System.out.println("num refs: " + sender.getReferences().size());
+
+ System.out.println("num toggles: " + toggler.getNumToggles());
+
+ }
+
+ // Inner classes ---------------------------------------------------------------
+
+ class Sender extends Thread
+ {
+ private volatile Exception e;
+
+ private Queue queue;
+
+ private long testTime;
+
+ private volatile int i;
+
+ public Exception getException()
+ {
+ return e;
+ }
+
+ private List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ public List<MessageReference> getReferences()
+ {
+ return refs;
+ }
+
+ Sender(Queue queue, long testTime)
+ {
+ this.testTime = testTime;
+
+ this.queue = queue;
+ }
+
+ public void run()
+ {
+ long start = System.currentTimeMillis();
+
+ while (System.currentTimeMillis() - start < testTime)
+ {
+ Message message = generateMessage(i);
+
+ MessageReference ref = message.createReference(queue);
+
+ queue.addLast(ref);
+
+ refs.add(ref);
+
+ i++;
+ }
+ }
+ }
+
+ class Toggler extends Thread
+ {
+ private volatile Exception e;
+
+ private Queue queue;
+
+ private FakeConsumer consumer;
+
+ private long testTime;
+
+ private boolean toggle;
+
+ private volatile int numToggles;
+
+ public int getNumToggles()
+ {
+ return numToggles;
+ }
+
+ public Exception getException()
+ {
+ return e;
+ }
+
+ Toggler(Queue queue, FakeConsumer consumer, long testTime)
+ {
+ this.testTime = testTime;
+
+ this.queue = queue;
+
+ this.consumer = consumer;
+ }
+
+ public void run()
+ {
+ long start = System.currentTimeMillis();
+
+ while (System.currentTimeMillis() - start < testTime)
+ {
+ if (toggle)
+ {
+ consumer.setStatusImmediate(HandleStatus.BUSY);
+ }
+ else
+ {
+ consumer.setStatusImmediate(HandleStatus.HANDLED);
+
+ queue.deliver();
+ }
+ toggle = !toggle;
+
+ numToggles++;
+ }
+ }
+ }
+
+}
+
+
+
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/timing/QueueTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/timing/QueueTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/timing/QueueTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,225 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.test.timing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.impl.test.unit.fakes.FakeConsumer;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A timing-sensitive QueueTest
+ *
+ * All the queue tests which are timing sensitive - go in here
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class QueueTest extends UnitTestCase
+{
+ private static final long TIMEOUT = 10000;
+
+ // The tests ----------------------------------------------------------------
+
+ public void testScheduledDirect()
+ {
+ testScheduled(true);
+ }
+
+ public void testScheduledQueueing()
+ {
+ testScheduled(false);
+ }
+
+ public void testScheduledNoConsumer() throws Exception
+ {
+ Queue queue = new QueueImpl(1);
+
+ //Send one scheduled
+
+ long now = System.currentTimeMillis();
+
+ MessageReference ref1 = generateReference(queue, 1);
+ ref1.setScheduledDeliveryTime(now + 7000);
+ queue.addLast(ref1);
+
+ //Send some non scheduled messages
+
+ MessageReference ref2 = generateReference(queue, 2);
+ queue.addLast(ref2);
+ MessageReference ref3 = generateReference(queue, 3);
+ queue.addLast(ref3);
+ MessageReference ref4 = generateReference(queue, 4);
+ queue.addLast(ref4);
+
+
+ //Now send some more scheduled messages
+
+ MessageReference ref5 = generateReference(queue, 5);
+ ref5.setScheduledDeliveryTime(now + 5000);
+ queue.addLast(ref5);
+
+ MessageReference ref6 = generateReference(queue, 6);
+ ref6.setScheduledDeliveryTime(now + 4000);
+ queue.addLast(ref6);
+
+ MessageReference ref7 = generateReference(queue, 7);
+ ref7.setScheduledDeliveryTime(now + 3000);
+ queue.addLast(ref7);
+
+ MessageReference ref8 = generateReference(queue, 8);
+ ref8.setScheduledDeliveryTime(now + 6000);
+ queue.addLast(ref8);
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ //Scheduled refs are added back to *FRONT* of queue - otherwise if there were many messages in the queue
+ //They may get stranded behind a big backlog
+
+ refs.add(ref1);
+ refs.add(ref8);
+ refs.add(ref5);
+ refs.add(ref6);
+ refs.add(ref7);
+
+ refs.add(ref2);
+ refs.add(ref3);
+ refs.add(ref4);
+
+ Thread.sleep(7500);
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+ }
+
+ private void testScheduled(boolean direct)
+ {
+ Queue queue = new QueueImpl(1);
+
+ FakeConsumer consumer = null;
+
+ if (direct)
+ {
+ consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+ }
+
+ //Send one scheduled
+
+ long now = System.currentTimeMillis();
+
+ MessageReference ref1 = generateReference(queue, 1);
+ ref1.setScheduledDeliveryTime(now + 7000);
+ queue.addLast(ref1);
+
+ //Send some non scheduled messages
+
+ MessageReference ref2 = generateReference(queue, 2);
+ queue.addLast(ref2);
+ MessageReference ref3 = generateReference(queue, 3);
+ queue.addLast(ref3);
+ MessageReference ref4 = generateReference(queue, 4);
+ queue.addLast(ref4);
+
+
+ //Now send some more scheduled messages
+
+ MessageReference ref5 = generateReference(queue, 5);
+ ref5.setScheduledDeliveryTime(now + 5000);
+ queue.addLast(ref5);
+
+ MessageReference ref6 = generateReference(queue, 6);
+ ref6.setScheduledDeliveryTime(now + 4000);
+ queue.addLast(ref6);
+
+ MessageReference ref7 = generateReference(queue, 7);
+ ref7.setScheduledDeliveryTime(now + 3000);
+ queue.addLast(ref7);
+
+ MessageReference ref8 = generateReference(queue, 8);
+ ref8.setScheduledDeliveryTime(now + 6000);
+ queue.addLast(ref8);
+
+ if (!direct)
+ {
+ consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+ }
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ refs.add(ref2);
+ refs.add(ref3);
+ refs.add(ref4);
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+
+ refs.clear();
+ consumer.getReferences().clear();
+
+
+ MessageReference ref = consumer.waitForNextReference(TIMEOUT);
+ assertEquals(ref7, ref);
+ long now2 = System.currentTimeMillis();
+ assertTrue(now2 - now >= 3000);
+
+ ref = consumer.waitForNextReference(TIMEOUT);
+ assertEquals(ref6, ref);
+ now2 = System.currentTimeMillis();
+ assertTrue(now2 - now >= 4000);
+
+ ref = consumer.waitForNextReference(TIMEOUT);
+ assertEquals(ref5, ref);
+ now2 = System.currentTimeMillis();
+ assertTrue(now2 - now >= 5000);
+
+ ref = consumer.waitForNextReference(TIMEOUT);
+ assertEquals(ref8, ref);
+ now2 = System.currentTimeMillis();
+ assertTrue(now2 - now >= 6000);
+
+ ref = consumer.waitForNextReference(TIMEOUT);
+ assertEquals(ref1, ref);
+ now2 = System.currentTimeMillis();
+ assertTrue(now2 - now >= 7000);
+
+ assertTrue(consumer.getReferences().isEmpty());
+ }
+
+ // Inner classes ---------------------------------------------------------------
+
+}
+
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/MessageTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/MessageTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/MessageTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,282 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.test.unit;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.messaging.newcore.impl.MessageImpl;
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * Tests for Message and MessageReference
+ *
+ * TODO - Test streaming and destreaming
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class MessageTest extends UnitTestCase
+{
+ public void testCreateMessage1()
+ {
+ long id = 56465;
+ int type = 655;
+ boolean reliable = true;
+ long expiration = 6712671;
+ long timestamp = 82798172;
+ byte priority = 32;
+
+ Message message = new MessageImpl(id, type, reliable, expiration, timestamp, priority);
+
+ assertEquals(id, message.getMessageID());
+ assertEquals(type, message.getType());
+ assertEquals(reliable, message.isReliable());
+ assertEquals(timestamp, message.getTimestamp());
+ assertEquals(priority, message.getPriority());
+
+ reliable = false;
+
+ message = new MessageImpl(id, type, reliable, expiration, timestamp, priority);
+
+ assertEquals(id, message.getMessageID());
+ assertEquals(type, message.getType());
+ assertEquals(reliable, message.isReliable());
+ assertEquals(timestamp, message.getTimestamp());
+ assertEquals(priority, message.getPriority());
+ }
+
+ public void testSetAndGetMessageID()
+ {
+ Message message = new MessageImpl();
+
+ long id = 765432;
+ message.setMessageID(id);
+ assertEquals(id, message.getMessageID());
+ }
+
+ public void testSetAndGetDestination()
+ {
+ Message message = new MessageImpl();
+
+ assertNull(message.getDestination());
+ String dest = "myDest";
+ message.setDestination(dest);
+ assertEquals(dest, message.getDestination());
+ }
+
+ public void testSetAndGetReliable()
+ {
+ Message message = new MessageImpl();
+
+ boolean reliable = true;
+ message.setReliable(reliable);
+ assertEquals(reliable, message.isReliable());
+
+ reliable = false;
+ message.setReliable(reliable);
+ assertEquals(reliable, message.isReliable());
+ }
+
+ public void testSetAndGetExpiration()
+ {
+ Message message = new MessageImpl();
+
+ long expiration = System.currentTimeMillis() + 10000;
+ message.setExpiration(expiration);
+ assertEquals(expiration, message.getExpiration());
+ assertFalse(message.isExpired());
+ message.setExpiration(System.currentTimeMillis() - 1);
+ assertTrue(message.isExpired());
+
+ expiration = 0; //O means never expire
+ message.setExpiration(expiration);
+ assertEquals(expiration, message.getExpiration());
+ assertFalse(message.isExpired());
+ }
+
+ public void testSetAndGetTimestamp()
+ {
+ Message message = new MessageImpl();
+
+ long timestamp = System.currentTimeMillis();
+ message.setTimestamp(timestamp);
+ assertEquals(timestamp, message.getTimestamp());
+ }
+
+ public void testSetAndGetPriority()
+ {
+ Message message = new MessageImpl();
+ byte priority = 7;
+ message.setPriority(priority);
+ assertEquals(priority, message.getPriority());
+ }
+
+ public void testSetAndGetConnectionID()
+ {
+ Message message = new MessageImpl();
+
+ assertNull(message.getConnectionID());
+ String connectionID = "conn123";
+ message.setConnectionID(connectionID);
+ assertEquals(connectionID, message.getConnectionID());
+ }
+
+ public void testSetAndGetPayload()
+ {
+ Message message = new MessageImpl();
+
+ assertNull(message.getPayload());
+
+ byte[] bytes = "blah blah blah".getBytes();
+ message.setPayload(bytes);
+
+ assertByteArraysEquivalent(bytes, message.getPayload());
+ }
+
+ public void testHeaders()
+ {
+ Message message = new MessageImpl();
+
+ assertNotNull(message.getHeaders());
+ assertTrue(message.getHeaders().isEmpty());
+
+ String key1 = "key1";
+ String val1 = "wibble";
+ String key2 = "key2";
+ Object val2 = new Object();
+ String key3 = "key3";
+ Double val3 = new Double(123.456);
+ Long val4 = new Long(77777);
+ message.putHeader(key1, val1);
+ assertEquals(val1, message.getHeaders().get(key1));
+ assertEquals(1, message.getHeaders().size());
+ assertTrue(message.containsHeader(key1));
+ assertFalse(message.containsHeader("does not exist"));
+ message.putHeader(key2, val2);
+ assertEquals(val2, message.getHeaders().get(key2));
+ assertEquals(2, message.getHeaders().size());
+ assertTrue(message.containsHeader(key2));
+ message.putHeader(key3, val3);
+ assertEquals(val3, message.getHeaders().get(key3));
+ assertEquals(3, message.getHeaders().size());
+ assertTrue(message.containsHeader(key3));
+ message.putHeader(key3, val4);
+ assertEquals(val4, message.getHeaders().get(key3));
+ assertEquals(3, message.getHeaders().size());
+ assertEquals(val2, message.removeHeader(key2));
+ assertEquals(2, message.getHeaders().size());
+ assertFalse(message.containsHeader(key2));
+ assertNull(message.removeHeader("does not exist"));
+ assertEquals(val1, message.removeHeader(key1));
+ assertFalse(message.containsHeader(key2));
+ assertEquals(1, message.getHeaders().size());
+ assertEquals(val3, message.removeHeader(key3));
+ assertFalse(message.containsHeader(key3));
+ assertTrue(message.getHeaders().isEmpty());
+ }
+
+ public void testEquals()
+ {
+ Message message1 = new MessageImpl();
+ message1.setMessageID(1);
+
+ Message message2 = new MessageImpl();
+ message2.setMessageID(2);
+
+ Message message3 = new MessageImpl();
+ message3.setMessageID(1);
+
+ assertTrue(message1.equals(message1));
+ assertTrue(message2.equals(message2));
+ assertTrue(message3.equals(message3));
+
+ assertFalse(message1.equals(message2));
+ assertFalse(message2.equals(message1));
+
+ assertFalse(message2.equals(message3));
+ assertFalse(message3.equals(message2));
+
+ assertTrue(message1.equals(message3));
+ assertTrue(message3.equals(message1));
+
+ }
+
+ public void testHashcode()
+ {
+ long id1 = 6567575;
+ Message message1 = new MessageImpl();
+ message1.setMessageID(id1);
+
+ assertEquals((int) ((id1 >>> 32) ^ id1), message1.hashCode());
+ }
+
+ public void testMessageReference()
+ {
+ Message message = new MessageImpl();
+
+ assertTrue(message.getReferences().isEmpty());
+
+ Queue queue1 = new QueueImpl(1);
+ Queue queue2 = new QueueImpl(2);
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ MessageReference ref1 = message.createReference(queue1);
+ refs.add(ref1);
+ MessageReference ref2 = message.createReference(queue2);
+ refs.add(ref2);
+ MessageReference ref3 = message.createReference(queue1);
+ refs.add(ref3);
+ MessageReference ref4 = message.createReference(queue2);
+ refs.add(ref4);
+
+ assertRefListsIdenticalRefs(refs, message.getReferences());
+
+ assertEquals(queue1, ref1.getQueue());
+ assertEquals(queue2, ref2.getQueue());
+ assertEquals(queue1, ref3.getQueue());
+ assertEquals(queue2, ref4.getQueue());
+
+ int deliveryCount = 65235;
+ ref1.setDeliveryCount(deliveryCount);
+ assertEquals(deliveryCount, ref1.getDeliveryCount());
+
+ long scheduledDeliveryTime = 908298123;
+ ref1.setScheduledDeliveryTime(scheduledDeliveryTime);
+ assertEquals(scheduledDeliveryTime, ref1.getScheduledDeliveryTime());
+
+ Queue queue3 = new QueueImpl(3);
+ MessageReference ref5 = ref1.copy(queue3);
+
+ assertEquals(deliveryCount, ref5.getDeliveryCount());
+ assertEquals(scheduledDeliveryTime, ref5.getScheduledDeliveryTime());
+ assertEquals(queue3, ref5.getQueue());
+ }
+
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/QueueTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/QueueTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/QueueTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,1080 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.test.unit;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.impl.RoundRobinDistributionPolicy;
+import org.jboss.messaging.newcore.impl.test.unit.fakes.FakeConsumer;
+import org.jboss.messaging.newcore.impl.test.unit.fakes.FakeFilter;
+import org.jboss.messaging.newcore.intf.Consumer;
+import org.jboss.messaging.newcore.intf.DistributionPolicy;
+import org.jboss.messaging.newcore.intf.Filter;
+import org.jboss.messaging.newcore.intf.HandleStatus;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A QueueTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class QueueTest extends UnitTestCase
+{
+ // The tests ----------------------------------------------------------------
+
+ public void testID()
+ {
+ final long id = 123;
+
+ Queue queue = new QueueImpl(id);
+
+ assertEquals(id, queue.getID());
+ }
+
+ public void testGetSetMaxSize()
+ {
+ final int maxSize = 123456;
+
+ final int id = 123;
+
+ Queue queue = new QueueImpl(id, null, maxSize);
+
+ assertEquals(id, queue.getID());
+
+ assertEquals(maxSize, queue.getMaxSize());
+
+ final int maxSize2 = 654321;
+
+ queue.setMaxSize(maxSize2);
+
+ assertEquals(maxSize2, queue.getMaxSize());
+ }
+
+ public void testAddRemoveConsumer()
+ {
+ Consumer cons1 = new FakeConsumer();
+
+ Consumer cons2 = new FakeConsumer();
+
+ Consumer cons3 = new FakeConsumer();
+
+ Queue queue = new QueueImpl(1);
+
+ assertEquals(0, queue.getConsumerCount());
+
+ queue.addConsumer(cons1);
+
+ assertEquals(1, queue.getConsumerCount());
+
+ assertTrue(queue.removeConsumer(cons1));
+
+ assertEquals(0, queue.getConsumerCount());
+
+ queue.addConsumer(cons1);
+
+ queue.addConsumer(cons2);
+
+ queue.addConsumer(cons3);
+
+ assertEquals(3, queue.getConsumerCount());
+
+ assertFalse(queue.removeConsumer(new FakeConsumer()));
+
+ assertEquals(3, queue.getConsumerCount());
+
+ assertTrue(queue.removeConsumer(cons1));
+
+ assertEquals(2, queue.getConsumerCount());
+
+ assertTrue(queue.removeConsumer(cons2));
+
+ assertEquals(1, queue.getConsumerCount());
+
+ assertTrue(queue.removeConsumer(cons3));
+
+ assertEquals(0, queue.getConsumerCount());
+
+ assertFalse(queue.removeConsumer(cons3));
+ }
+
+ public void testGetSetDistributionPolicy()
+ {
+ Queue queue = new QueueImpl(1);
+
+ assertNotNull(queue.getDistributionPolicy());
+
+ assertTrue(queue.getDistributionPolicy() instanceof RoundRobinDistributionPolicy);
+
+ DistributionPolicy policy = new DummyDistributionPolicy();
+
+ queue.setDistributionPolicy(policy);
+
+ assertEquals(policy, queue.getDistributionPolicy());
+ }
+
+ public void testGetSetFilter()
+ {
+ Queue queue = new QueueImpl(1);
+
+ assertNull(queue.getFilter());
+
+ Filter filter = new FakeFilter();
+
+ queue.setFilter(filter);
+
+ assertEquals(filter, queue.getFilter());
+
+ queue = new QueueImpl(1, filter);
+
+ assertEquals(filter, queue.getFilter());
+ }
+
+ public void testDefaultMaxSize()
+ {
+ Queue queue = new QueueImpl(1);
+
+ assertEquals(-1, queue.getMaxSize());
+
+ queue = new QueueImpl(1, new FakeFilter());
+
+ assertEquals(-1, queue.getMaxSize());
+ }
+
+ public void testSimpleAddLast()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 10;
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(numMessages, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ }
+
+ public void testSimpleDirectDelivery()
+ {
+ Queue queue = new QueueImpl(1);
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+ }
+
+ public void testSimpleNonDirectDelivery()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(10, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ //Now add a consumer
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ assertTrue(consumer.getReferences().isEmpty());
+ assertEquals(10, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ queue.deliver();
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+ }
+
+ public void testBusyConsumer()
+ {
+ Queue queue = new QueueImpl(1);
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ consumer.setStatusImmediate(HandleStatus.BUSY);
+
+ queue.addConsumer(consumer);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(10, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ queue.deliver();
+
+ assertEquals(10, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+ assertTrue(consumer.getReferences().isEmpty());
+
+ consumer.setStatusImmediate(HandleStatus.HANDLED);
+
+ queue.deliver();
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+ }
+
+ public void testBusyConsumerThenAddMoreMessages()
+ {
+ Queue queue = new QueueImpl(1);
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ consumer.setStatusImmediate(HandleStatus.BUSY);
+
+ queue.addConsumer(consumer);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(10, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ queue.deliver();
+
+ assertEquals(10, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+ assertTrue(consumer.getReferences().isEmpty());
+
+ for (int i = numMessages; i < numMessages * 2; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(20, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+ assertTrue(consumer.getReferences().isEmpty());
+
+ consumer.setStatusImmediate(HandleStatus.HANDLED);
+
+ for (int i = numMessages * 2; i < numMessages * 3; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ queue.deliver();
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+ }
+
+ public void testAddFirstAddLast()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs1 = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs1.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ LinkedList<MessageReference> refs2 = new LinkedList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i + numMessages);
+
+ refs2.addFirst(ref);
+
+ queue.addFirst(ref);
+ }
+
+ List<MessageReference> refs3 = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i + 2 * numMessages);
+
+ refs3.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+
+ List<MessageReference> allRefs = new ArrayList<MessageReference>();
+
+ allRefs.addAll(refs2);
+ allRefs.addAll(refs1);
+ allRefs.addAll(refs3);
+
+ assertRefListsIdenticalRefs(allRefs, consumer.getReferences());
+ }
+
+
+ public void testChangeConsumersAndDeliver()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(numMessages, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ FakeConsumer cons1 = new FakeConsumer();
+
+ queue.addConsumer(cons1);
+
+ queue.deliver();
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertRefListsIdenticalRefs(refs, cons1.getReferences());
+
+ FakeConsumer cons2 = new FakeConsumer();
+
+ queue.addConsumer(cons2);
+
+ assertEquals(2, queue.getConsumerCount());
+
+ cons1.getReferences().clear();
+
+ refs.clear();
+
+ for (int i = 0; i < 2 * numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertEquals(numMessages, cons1.getReferences().size());
+
+ assertEquals(numMessages, cons2.getReferences().size());
+
+ cons1.getReferences().clear();
+ cons2.getReferences().clear();
+ refs.clear();
+
+ FakeConsumer cons3 = new FakeConsumer();
+
+ queue.addConsumer(cons3);
+
+ assertEquals(3, queue.getConsumerCount());
+
+ for (int i = 0; i < 3 * numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertEquals(numMessages, cons1.getReferences().size());
+
+ assertEquals(numMessages, cons2.getReferences().size());
+
+ assertEquals(numMessages, cons3.getReferences().size());
+
+ queue.removeConsumer(cons1);
+
+ cons3.getReferences().clear();
+ cons2.getReferences().clear();
+ refs.clear();
+
+ for (int i = 0; i < 2 * numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertEquals(numMessages, cons2.getReferences().size());
+
+ assertEquals(numMessages, cons3.getReferences().size());
+
+ queue.removeConsumer(cons3);
+
+ cons2.getReferences().clear();
+ refs.clear();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertEquals(numMessages, cons2.getReferences().size());
+
+ }
+
+ public void testRoundRobinWithQueueing()
+ {
+ Queue queue = new QueueImpl(1);
+
+ assertTrue(queue.getDistributionPolicy() instanceof RoundRobinDistributionPolicy);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ //Test first with queueing
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ FakeConsumer cons1 = new FakeConsumer();
+
+ FakeConsumer cons2 = new FakeConsumer();
+
+ queue.addConsumer(cons1);
+
+ queue.addConsumer(cons2);
+
+ queue.deliver();
+
+ assertEquals(numMessages / 2, cons1.getReferences().size());
+
+ assertEquals(numMessages / 2, cons2.getReferences().size());
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref;
+
+ ref = (i % 2 == 0) ? cons1.getReferences().get(i / 2) : cons2.getReferences().get(i / 2);
+
+ assertEquals(refs.get(i), ref);
+ }
+ }
+
+ public void testRoundRobinDirect()
+ {
+ Queue queue = new QueueImpl(1);
+
+ assertTrue(queue.getDistributionPolicy() instanceof RoundRobinDistributionPolicy);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ FakeConsumer cons1 = new FakeConsumer();
+
+ FakeConsumer cons2 = new FakeConsumer();
+
+ queue.addConsumer(cons1);
+
+ queue.addConsumer(cons2);
+
+ queue.deliver();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(numMessages / 2, cons1.getReferences().size());
+
+ assertEquals(numMessages / 2, cons2.getReferences().size());
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref;
+
+ ref = (i % 2 == 0) ? cons1.getReferences().get(i / 2) : cons2.getReferences().get(i / 2);
+
+ assertEquals(refs.get(i), ref);
+ }
+ }
+
+ public void testRemoveAllReferences()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ queue.addLast(ref);
+ }
+
+ assertEquals(numMessages, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ queue.removeAllReferences();
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+
+ assertTrue(consumer.getReferences().isEmpty());
+ }
+
+ public void testMaxSize()
+ {
+ final int maxSize = 20;
+
+ Queue queue = new QueueImpl(1, null, maxSize);
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < maxSize; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ assertEquals(HandleStatus.BUSY, queue.addLast(ref));
+ }
+
+ assertEquals(maxSize, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ //Try to add more
+
+ for (int i = 0; i < 10; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ assertEquals(HandleStatus.BUSY, queue.addLast(ref));
+ }
+
+ assertEquals(maxSize, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ // Try to add at front too
+
+ for (int i = 0; i < 10; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ assertEquals(HandleStatus.BUSY, queue.addLast(ref));
+ }
+
+ //Increase the max size
+
+ queue.setMaxSize(2 * queue.getMaxSize());
+
+ for (int i = 0; i < maxSize; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ refs.add(ref);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref));
+ }
+
+ assertEquals(maxSize * 2, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ //Now try and decrease maxSize
+
+ try
+ {
+ queue.setMaxSize(maxSize);
+
+ fail("Should throw exception");
+ }
+ catch (IllegalArgumentException e)
+ {
+ //Ok
+ }
+
+ assertEquals(2 * maxSize, queue.getMaxSize());
+ }
+
+ public void testQueueWithFilter()
+ {
+ Filter filter = new FakeFilter("fruit", "orange");
+
+ Queue queue = new QueueImpl(1, filter);
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ MessageReference ref1 = generateReference(queue, 1);
+
+ ref1.getMessage().putHeader("fruit", "banana");
+
+ assertEquals(HandleStatus.NO_MATCH, queue.addLast(ref1));
+
+ MessageReference ref2 = generateReference(queue, 2);
+
+ ref2.getMessage().putHeader("cheese", "stilton");
+
+ assertEquals(HandleStatus.NO_MATCH, queue.addLast(ref2));
+
+ MessageReference ref3 = generateReference(queue, 3);
+
+ ref3.getMessage().putHeader("cake", "sponge");
+
+ assertEquals(HandleStatus.NO_MATCH, queue.addLast(ref3));
+
+ MessageReference ref4 = generateReference(queue, 4);
+
+ ref4.getMessage().putHeader("fruit", "orange");
+
+ refs.add(ref4);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref4));
+
+ MessageReference ref5 = generateReference(queue, 5);
+
+ ref5.getMessage().putHeader("fruit", "apple");
+
+ assertEquals(HandleStatus.NO_MATCH, queue.addLast(ref5));
+
+ MessageReference ref6 = generateReference(queue, 6);
+
+ ref6.getMessage().putHeader("fruit", "orange");
+
+ refs.add(ref6);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref6));
+
+ //Add a few first
+
+ MessageReference ref7 = generateReference(queue, 7);
+
+ ref7.getMessage().putHeader("fruit", "banana");
+
+ assertEquals(HandleStatus.NO_MATCH, queue.addFirst(ref7));
+
+ MessageReference ref8 = generateReference(queue, 8);
+
+ ref8.getMessage().putHeader("fruit", "nectarine");
+
+ assertEquals(HandleStatus.NO_MATCH, queue.addFirst(ref8));
+
+ MessageReference ref9 = generateReference(queue, 9);
+
+ ref9.getMessage().putHeader("fruit", "orange");
+
+ assertEquals(HandleStatus.HANDLED, queue.addFirst(ref9));
+
+ List<MessageReference> newRefs = new ArrayList<MessageReference>();
+
+ newRefs.add(ref9);
+ newRefs.addAll(refs);
+
+ queue.setFilter(null);
+
+ MessageReference ref10 = generateReference(queue, 10);
+
+ ref10.getMessage().putHeader("sport", "skiing");
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref10));
+
+ newRefs.add(ref10);
+
+ assertEquals(4, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+
+ assertEquals(0, queue.getMessageCount());
+ assertEquals(0, queue.getScheduledCount());
+
+ assertRefListsIdenticalRefs(newRefs, consumer.getReferences());
+ }
+
+ public void testWithPriorities()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 10;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ ref.getMessage().setPriority((byte)i);
+
+ refs.add(ref);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref));
+ }
+
+ FakeConsumer consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+
+ List<MessageReference> receivedRefs = consumer.getReferences();
+
+ //Should be in reverse order
+
+ assertEquals(refs.size(), receivedRefs.size());
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ assertEquals(refs.get(i), receivedRefs.get(9 - i));
+ }
+
+ //But if we send more - since we are now in direct mode - the order will be the send order
+ //since the refs don't get queued
+
+ consumer.clearReferences();
+
+ refs.clear();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ ref.getMessage().setPriority((byte)i);
+
+ refs.add(ref);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref));
+ }
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+ }
+
+ public void testConsumerWithFiltersDirect()
+ {
+ testConsumerWithFilters(true);
+ }
+
+ public void testConsumerWithFiltersQueueing()
+ {
+ testConsumerWithFilters(false);
+ }
+
+ public void testList()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 20;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ queue.addLast(ref);
+
+ refs.add(ref);
+ }
+
+ assertEquals(numMessages, queue.getMessageCount());
+
+ List<MessageReference> list = queue.list(null);
+
+ assertRefListsIdenticalRefs(refs, list);
+ }
+
+ public void testListWithFilter()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 20;
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = generateReference(queue, i);
+
+ if (i % 2 == 0)
+ {
+ ref.getMessage().putHeader("god", "dog");
+ }
+
+ queue.addLast(ref);
+
+ refs.add(ref);
+ }
+
+ assertEquals(numMessages, queue.getMessageCount());
+
+ Filter filter = new FakeFilter("god", "dog");
+
+ List<MessageReference> list = queue.list(filter);
+
+ assertEquals(numMessages / 2, list.size());
+
+ for (int i = 0; i < numMessages; i += 2)
+ {
+ assertEquals(refs.get(i), list.get(i / 2));
+ }
+ }
+
+ /*
+ public void testQuickSpeedTest()
+ {
+ Queue queue = new QueueImpl(1);
+
+ final int numMessages = 1000000;
+
+ FakeConsumer cons = new FakeConsumer();
+
+ queue.addConsumer(cons);
+
+ long start = System.currentTimeMillis();
+
+ for (int i = 0; i < numMessages; i++)
+ {
+ MessageReference ref = this.generateReference(1);
+
+ queue.addLast(ref);
+ }
+
+ long end = System.currentTimeMillis();
+
+ double rate = 1000 * (double)numMessages / (end - start);
+
+ System.out.println("Rate: " + rate);
+
+ assertEquals(numMessages, cons.getReferences().size());
+ }
+ */
+
+ // Private ------------------------------------------------------------------------------
+
+ private void testConsumerWithFilters(boolean direct)
+ {
+ Queue queue = new QueueImpl(1);
+
+ Filter filter = new FakeFilter("fruit", "orange");
+
+ FakeConsumer consumer = new FakeConsumer(filter);
+
+ if (direct)
+ {
+ queue.addConsumer(consumer);
+ }
+
+ List<MessageReference> refs = new ArrayList<MessageReference>();
+
+ MessageReference ref1 = generateReference(queue, 1);
+
+ ref1.getMessage().putHeader("fruit", "banana");
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref1));
+
+ MessageReference ref2 = generateReference(queue, 2);
+
+ ref2.getMessage().putHeader("cheese", "stilton");
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref2));
+
+ MessageReference ref3 = generateReference(queue, 3);
+
+ ref3.getMessage().putHeader("cake", "sponge");
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref3));
+
+ MessageReference ref4 = generateReference(queue, 4);
+
+ ref4.getMessage().putHeader("fruit", "orange");
+
+ refs.add(ref4);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref4));
+
+ MessageReference ref5 = generateReference(queue, 5);
+
+ ref5.getMessage().putHeader("fruit", "apple");
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref5));
+
+ MessageReference ref6 = generateReference(queue, 6);
+
+ ref6.getMessage().putHeader("fruit", "orange");
+
+ refs.add(ref6);
+
+ assertEquals(HandleStatus.HANDLED, queue.addLast(ref6));
+
+ if (!direct)
+ {
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+ }
+
+ assertEquals(4, queue.getMessageCount());
+
+ assertEquals(2, consumer.getReferences().size());
+
+ assertRefListsIdenticalRefs(refs, consumer.getReferences());
+
+ queue.removeConsumer(consumer);
+
+ consumer = new FakeConsumer();
+
+ queue.addConsumer(consumer);
+
+ queue.deliver();
+
+ assertEquals(0, queue.getMessageCount());
+
+ assertEquals(4, consumer.getReferences().size());
+ }
+
+ // Inner classes ---------------------------------------------------------------
+
+ class DummyDistributionPolicy implements DistributionPolicy
+ {
+ public int select(List<Consumer> consumers, int lastPos)
+ {
+ return 0;
+ }
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/RoundRobinDistributionPolicyTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/RoundRobinDistributionPolicyTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/RoundRobinDistributionPolicyTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,74 @@
+package org.jboss.messaging.newcore.impl.test.unit;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.messaging.newcore.impl.RoundRobinDistributionPolicy;
+import org.jboss.messaging.newcore.impl.test.unit.fakes.FakeConsumer;
+import org.jboss.messaging.newcore.intf.Consumer;
+import org.jboss.messaging.newcore.intf.DistributionPolicy;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A RoundRobinDistributionPolicyTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class RoundRobinDistributionPolicyTest extends UnitTestCase
+{
+
+ public void testNoConsumers()
+ {
+ List<Consumer> consumers = new ArrayList<Consumer>();
+
+ DistributionPolicy dp = new RoundRobinDistributionPolicy();
+
+ int pos = dp.select(consumers, -1);
+
+ assertEquals(0, pos);
+ }
+
+ public void testConsumers()
+ {
+ List<Consumer> consumers = new ArrayList<Consumer>();
+
+ consumers.add(new FakeConsumer());
+ consumers.add(new FakeConsumer());
+ consumers.add(new FakeConsumer());
+
+ DistributionPolicy dp = new RoundRobinDistributionPolicy();
+
+ int pos = -1;
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(0, pos);
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(1, pos);
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(2, pos);
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(0, pos);
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(1, pos);
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(2, pos);
+
+ pos = dp.select(consumers, pos);
+
+ assertEquals(0, pos);
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/TransactionTest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/TransactionTest.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/TransactionTest.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,326 @@
+package org.jboss.messaging.newcore.impl.test.unit;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.xa.Xid;
+
+import org.easymock.EasyMock;
+import org.jboss.messaging.newcore.impl.QueueImpl;
+import org.jboss.messaging.newcore.impl.TransactionImpl;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.PersistenceManager;
+import org.jboss.messaging.newcore.intf.Queue;
+import org.jboss.messaging.newcore.intf.Transaction;
+import org.jboss.messaging.newcore.intf.TransactionSynchronization;
+import org.jboss.messaging.test.unit.UnitTestCase;
+
+/**
+ *
+ * A TransactionTest
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class TransactionTest extends UnitTestCase
+{
+
+ public void test1PCCommit() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Transaction tx = new TransactionImpl(msgsToAdd, refsToRemove, true);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ pm.commitTransaction(msgsToAdd, refsToRemove);
+
+ EasyMock.replay(pm);
+
+ tx.commit(pm);
+
+ EasyMock.verify(pm);
+
+ assertEquals(ref1, queue.list(null).get(0));
+ }
+
+ public void test1PCRollback() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Transaction tx = new TransactionImpl(msgsToAdd, refsToRemove, true);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ EasyMock.replay(pm);
+
+ tx.rollback(pm);
+
+ EasyMock.verify(pm);
+
+ assertTrue(queue.list(null).isEmpty());
+ }
+
+ public void test1PCPrepare() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Transaction tx = new TransactionImpl(msgsToAdd, refsToRemove, true);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ try
+ {
+ tx.prepare(pm);
+ fail("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //OK
+ }
+
+ assertTrue(queue.list(null).isEmpty());
+ }
+
+ public void test2PCPrepareCommit() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Xid xid = generateXid();
+
+ Transaction tx = new TransactionImpl(xid, msgsToAdd, refsToRemove, true);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ pm.prepareTransaction(xid, msgsToAdd, refsToRemove);
+
+ EasyMock.replay(pm);
+
+ tx.prepare(pm);
+
+ EasyMock.verify(pm);
+
+ EasyMock.reset(pm);
+
+ pm.commitPreparedTransaction(xid);
+
+ EasyMock.replay(pm);
+
+ tx.commit(pm);
+
+ EasyMock.verify(pm);
+ }
+
+ public void test2PCCommitBeforePrepare() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Xid xid = generateXid();
+
+ Transaction tx = new TransactionImpl(xid, msgsToAdd, refsToRemove, true);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ try
+ {
+ tx.commit(pm);
+
+ fail ("Should throw exception");
+ }
+ catch (IllegalStateException e)
+ {
+ //Ok
+ }
+ }
+
+ public void test2PCPrepareRollback() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Xid xid = generateXid();
+
+ Transaction tx = new TransactionImpl(xid, msgsToAdd, refsToRemove, true);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ pm.prepareTransaction(xid, msgsToAdd, refsToRemove);
+
+ EasyMock.replay(pm);
+
+ tx.prepare(pm);
+
+ EasyMock.verify(pm);
+
+ EasyMock.reset(pm);
+
+ pm.unprepareTransaction(xid, msgsToAdd, refsToRemove);
+
+ EasyMock.replay(pm);
+
+ tx.rollback(pm);
+
+ EasyMock.verify(pm);
+ }
+
+ public void testSynchronizations() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Transaction tx = new TransactionImpl(msgsToAdd, refsToRemove, true);
+
+ TransactionSynchronization sync = EasyMock.createStrictMock(TransactionSynchronization.class);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ tx.addSynchronization(sync);
+
+ sync.beforeCommit();
+ sync.afterCommit();
+
+ EasyMock.replay(sync);
+
+ tx.commit(pm);
+
+ EasyMock.verify(sync);
+
+ EasyMock.reset(sync);
+
+ tx = new TransactionImpl(msgsToAdd, refsToRemove, true);
+
+ tx.addSynchronization(sync);
+
+ sync.beforeRollback();
+ sync.afterRollback();
+
+ EasyMock.replay(sync);
+
+ tx.rollback(pm);
+
+ EasyMock.verify(sync);
+ }
+
+ public void testSynchronizations2PC() throws Exception
+ {
+ List<Message> msgsToAdd = new ArrayList<Message>();
+
+ List<MessageReference> refsToRemove = new ArrayList<MessageReference>();
+
+ Queue queue = new QueueImpl(1);
+
+ MessageReference ref1 = this.generateReference(queue, 1);
+ msgsToAdd.add(ref1.getMessage());
+
+ MessageReference ref2 = this.generateReference(queue, 2);
+ refsToRemove.add(ref2);
+
+ Xid xid = generateXid();
+
+ Transaction tx = new TransactionImpl(xid, msgsToAdd, refsToRemove, true);
+
+ TransactionSynchronization sync = EasyMock.createStrictMock(TransactionSynchronization.class);
+
+ PersistenceManager pm = EasyMock.createStrictMock(PersistenceManager.class);
+
+ tx.addSynchronization(sync);
+
+ sync.beforeCommit();
+ sync.afterCommit();
+
+ EasyMock.replay(sync);
+
+ tx.prepare(pm);
+ tx.commit(pm);
+
+ EasyMock.verify(sync);
+
+ EasyMock.reset(sync);
+
+ xid = generateXid();
+
+ tx = new TransactionImpl(xid, msgsToAdd, refsToRemove, true);
+
+ tx.addSynchronization(sync);
+
+ sync.beforeRollback();
+ sync.afterRollback();
+
+ EasyMock.replay(sync);
+
+ tx.prepare(pm);
+ tx.rollback(pm);
+
+ EasyMock.verify(sync);
+ }
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeConsumer.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeConsumer.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeConsumer.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.test.unit.fakes;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jboss.messaging.newcore.intf.Consumer;
+import org.jboss.messaging.newcore.intf.Filter;
+import org.jboss.messaging.newcore.intf.HandleStatus;
+import org.jboss.messaging.newcore.intf.MessageReference;
+
+/**
+ *
+ * A FakeConsumer
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class FakeConsumer implements Consumer
+{
+ private HandleStatus statusToReturn = HandleStatus.HANDLED;
+
+ private HandleStatus newStatus;
+
+ private int delayCountdown = 0;
+
+ private LinkedList<MessageReference> references = new LinkedList<MessageReference>();
+
+ private Filter filter;
+
+ public FakeConsumer()
+ {
+ }
+
+ public FakeConsumer(Filter filter)
+ {
+ this.filter = filter;
+ }
+
+ public synchronized MessageReference waitForNextReference(long timeout)
+ {
+ while (references.isEmpty() && timeout > 0)
+ {
+ long start = System.currentTimeMillis();
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ timeout -= (System.currentTimeMillis() - start);
+ }
+
+ if (timeout <= 0)
+ {
+ throw new IllegalStateException("Timed out waiting for reference");
+ }
+
+ return references.removeFirst();
+ }
+
+ public synchronized void setStatusImmediate(HandleStatus newStatus)
+ {
+ this.statusToReturn = newStatus;
+ }
+
+ public synchronized void setStatusDelayed(HandleStatus newStatus, int numReferences)
+ {
+ this.newStatus = newStatus;
+
+ this.delayCountdown = numReferences;
+ }
+
+ public synchronized List<MessageReference> getReferences()
+ {
+ return references;
+ }
+
+ public synchronized void clearReferences()
+ {
+ this.references.clear();
+ }
+
+ public synchronized HandleStatus handle(MessageReference reference)
+ {
+ if (filter != null)
+ {
+ if (filter.match(reference.getMessage()))
+ {
+ references.addLast(reference);
+ notify();
+
+ return HandleStatus.HANDLED;
+ }
+ else
+ {
+ return HandleStatus.NO_MATCH;
+ }
+ }
+
+ if (newStatus != null)
+ {
+ if (delayCountdown == 0)
+ {
+ statusToReturn = newStatus;
+
+ newStatus = null;
+ }
+ else
+ {
+ delayCountdown--;
+ }
+ }
+
+ if (statusToReturn == HandleStatus.HANDLED)
+ {
+ references.addLast(reference);
+ notify();
+ }
+
+ return statusToReturn;
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeFilter.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeFilter.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/impl/test/unit/fakes/FakeFilter.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.impl.test.unit.fakes;
+
+import org.jboss.messaging.newcore.intf.Filter;
+import org.jboss.messaging.newcore.intf.Message;
+
+/**
+ *
+ * A FakeFilter
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class FakeFilter implements Filter
+{
+ private String headerName;
+
+ private Object headerValue;
+
+ public FakeFilter(String headerName, Object headerValue)
+ {
+ this.headerName = headerName;
+
+ this.headerValue = headerValue;
+ }
+
+ public FakeFilter()
+ {
+ }
+
+ public boolean match(Message message)
+ {
+ if (headerName != null)
+ {
+ Object value = message.getHeader(headerName);
+
+ if (value != null && headerValue.equals(value))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public String getFilterString()
+ {
+ return null;
+ }
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/ClusteredQueue.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/ClusteredQueue.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/ClusteredQueue.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A ClusteredQueue
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface ClusteredQueue extends Queue
+{
+
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/Consumer.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/Consumer.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/Consumer.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+
+/**
+ *
+ * A Consumer
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface Consumer
+{
+ HandleStatus handle(MessageReference reference);
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/DistributionPolicy.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/DistributionPolicy.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/DistributionPolicy.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+import java.util.List;
+
+/**
+ *
+ * A DistributionPolicy
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface DistributionPolicy
+{
+ int select(List<Consumer> consumers, int lastPos);
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/Filter.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/Filter.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/Filter.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A Filter
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface Filter
+{
+ boolean match(Message message);
+
+ String getFilterString();
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/HandleStatus.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/HandleStatus.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/HandleStatus.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A HandleStatus
+ *
+ * HANDLED means the MessageReference was handled
+ *
+ * NO_MATCH means the MessageReference was rejected by a Filter
+ *
+ * BUSY means the MessageReference was rejected since the Consumer was busy
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public enum HandleStatus
+{
+ HANDLED, NO_MATCH, BUSY;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/Message.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/Message.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/Message.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,233 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.messaging.util.Streamable;
+
+/**
+ * A message is a routable instance that has a payload.
+ * The payload is opaque to the messaging system.
+ *
+ * @author <a href="mailto:ovidiu at feodorov.com">Ovidiu Feodorov</a>
+ * @author <a href="mailto:tim.fox"jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 3341 $</tt>
+ *
+ * $Id: Message.java 3341 2007-11-19 14:34:57Z timfox $
+ */
+public interface Message extends Streamable
+{
+ /**
+ * This header is set on a message when a message is sucked from one node of the cluster to another
+ * and order preservation is true.
+ * The header is checked when sucking messages and if order preservation is true then the message is not accepted.
+ * This is a basic way of ensuring message order is preserved.
+ */
+ public static final String CLUSTER_SUCKED = "SUCKED";
+
+ /**
+ * This header is set on a message when it is sucked from one node to another.
+ * If the header exists on the destination node, and the message is persistent, the message
+ * will be moved from one channel to the other by doing a simple database update
+ */
+ public static final String SOURCE_CHANNEL_ID = "SCID";
+
+ /**
+ * The scheduled delivery time for the message
+ */
+ public static final String SCHEDULED_DELIVERY_TIME = "SCHED";
+
+ /**
+ * @return The unique id of the message
+ */
+ long getMessageID();
+
+ /**
+ * Set the message id
+ *
+ * @param id
+ */
+ void setMessageID(long id);
+
+ /**
+ * Get the destination
+ * @return
+ */
+ String getDestination();
+
+ /**
+ * Set the destination
+ * @param destination
+ */
+ void setDestination(String destination);
+
+ /**
+ * @return true if the delivery must be guaranteed for this routable, false otherwise.
+ */
+ boolean isReliable();
+
+ /**
+ * Set whether message is reliable or not
+ * @param reliable
+ */
+ void setReliable(boolean reliable);
+
+ /**
+ * @return the time when this routable expires and must be removed
+ * from the system. A zero value means this routable never expires.
+ */
+ long getExpiration();
+
+ /**
+ *
+ * @return true if the message has expired
+ */
+ boolean isExpired();
+
+ /**
+ * Set the expiration for this message
+ *
+ * @param expiration
+ */
+ void setExpiration(long expiration);
+
+ /**
+ * @return the time (in GMT milliseconds) when this routable was delivered to the provider.
+ */
+ long getTimestamp();
+
+ /**
+ * Set the timestamp for this message
+ * @param timestamp The timestamp
+ */
+ void setTimestamp(long timestamp);
+
+ /**
+ *
+ * @return The priority (0-9) of the message
+ */
+ byte getPriority();
+
+ /**
+ * Get the priority of the message. Priorities range from 0 to 9.
+ * Where 0 is the lowest priority and 9 is the highest priority
+ * @param priority
+ */
+ void setPriority(byte priority);
+
+ /**
+ * Binds a header. If the header map previously contained a mapping for this name, the old value
+ * is replaced by the specified value.
+ *
+ * @return the value associated with the name or null if there is no mapping for the name. A null
+ * can also indicate that the header map previously associated null with the specified
+ * name.
+ */
+ Object putHeader(String name, Object value);
+
+ /**
+ * Returns the value corresponding to the header name. Returns null if the map contains no
+ * mapping for the name. A return value of null does not necessarily indicate that the map
+ * contains no mapping for the name; it's also possible that the map explicitly maps the name to
+ * null. The containsHeader() operation may be used to distinguish these two cases.
+ *
+ * @return the value associated with the header, or null if there is no mapping for the header.
+ */
+ Object getHeader(String name);
+
+ /**
+ * Removes the header.
+ *
+ * @return previous value associated with the header, or null if there was no mapping.
+ */
+ Object removeHeader(String name);
+
+ /**
+ * Returns true if the Routable contains the specified header.
+ */
+ boolean containsHeader(String name);
+
+ /**
+ *
+ * @return The message's headers
+ */
+ Map<String, Object> getHeaders();
+
+ /**
+ *
+ * @return The message's payload
+ */
+ byte[] getPayload();
+
+
+ /**
+ * Set the payload
+ *
+ * @param payload
+ */
+ void setPayload(byte[] payload);
+
+ /**
+ *
+ * @return The message's headers as byte array
+ */
+ byte[] getHeadersAsByteArray() throws Exception;
+
+ /**
+ *
+ * @return the type of the message
+ */
+ int getType();
+
+ /**
+ * Get the connection id
+ * @return
+ */
+ String getConnectionID();
+
+ /**
+ * Set the connection id
+ * @param connectionID
+ */
+ void setConnectionID(String connectionID);
+
+
+ /**
+ * @return a reference for this message
+ */
+ MessageReference createReference(Queue queue);
+
+ /**
+ *
+ * @return List of persisted references for this message
+ */
+ List<MessageReference> getReferences();
+
+ /**
+ * Make a copy of the message
+ *
+ * @return The copy
+ */
+ Message copy();
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/MessageReference.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/MessageReference.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/MessageReference.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ * A reference to a message.
+ *
+ * Channels store message references rather than the messages themselves.
+ *
+ * If many channels have contain the same reference this makes a lot of sense
+ *
+ * @author <a href="mailto:ovidiu at feodorov.com">Ovidiu Feodorov</a>
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 3020 $</tt>
+ *
+ * $Id: MessageReference.java 3020 2007-08-21 15:46:38Z timfox $
+ */
+public interface MessageReference
+{
+ Message getMessage();
+
+ MessageReference copy(Queue queue);
+
+ /**
+ *
+ * @return The time in the future that delivery will be delayed until, or zero if
+ * no scheduled delivery will occur
+ */
+ long getScheduledDeliveryTime();
+
+ void setScheduledDeliveryTime(long scheduledDeliveryTime);
+
+ /**
+ * @return the number of times delivery has been attempted for this routable
+ */
+ int getDeliveryCount();
+
+ void setDeliveryCount(int deliveryCount);
+
+ Queue getQueue();
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/MessagingComponent.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/MessagingComponent.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/MessagingComponent.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ * A MessagingComponent
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 2796 $</tt>
+ *
+ * $Id: MessagingComponent.java 2796 2007-06-25 22:24:41Z timfox $
+ *
+ */
+public interface MessagingComponent
+{
+ void start() throws Exception;
+
+ void stop() throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/PagingManager.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/PagingManager.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/PagingManager.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,15 @@
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A PagingManager
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface PagingManager extends MessagingComponent
+{
+ void pageReference(Queue queue, MessageReference ref);
+
+ MessageReference depageReference(Queue queue);
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/PersistenceManager.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/PersistenceManager.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/PersistenceManager.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,125 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.transaction.xa.Xid;
+
+/**
+ *
+ * A PersistenceManager
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface PersistenceManager extends MessagingComponent
+{
+ /**
+ * A single message, possible with many message references needs to be added to storage
+ * This would occur when a single reliable messages arrives on the server and needs to be routed
+ * to 1 or more queues.
+ * @param message
+ */
+ public void addMessage(Message message) throws Exception;
+
+ /**
+ * Delete a single reference. This would also delete the message if it is no longer referenced by any other
+ * references.
+ * This would occur on acknowledgement of a single reference
+ * @param message
+ */
+ void deleteReference(MessageReference reference) throws Exception;
+
+ /**
+ * Commit a transaction containing messages to add and references to remove
+ * @param messagesToAdd List of messages to add, or null if none
+ * @param referencesToRemove List of references to remove, or null if none
+ * @throws Exception
+ */
+ public void commitTransaction(List<Message> messagesToAdd, List<MessageReference> referencesToRemove) throws Exception;
+
+ /**
+ * Prepare a transaction containing messages to add and references to remove
+ * @param xid The Xid of the XA transaction
+ * @param messagesToAdd List of messages to add, or null if none
+ * @param referencesToRemove List of references to remove, or null if none
+ * @throws Exception
+ */
+ public void prepareTransaction(Xid xid, List<Message> messagesToAdd,
+ List<MessageReference> referencesToRemove) throws Exception;
+
+ /**
+ * Commit a prepared transaction
+ *
+ * @param xid
+ * @throws Exception
+ */
+ public void commitPreparedTransaction(Xid xid) throws Exception;
+
+
+ /**
+ * Unprepare a transaction containing messages to add and references to remove
+ * @param xid The Xid of the XA transaction
+ * @param messagesToAdd List of messages to add, or null if none
+ * @param referencesToRemove List of references to remove, or null if none
+ * @throws Exception
+ */
+ public void unprepareTransaction(Xid xid, List<Message> messagesToAdd,
+ List<MessageReference> referencesToRemove) throws Exception;
+
+
+ /**
+ * Update the delivery count of a reference
+ * @param queue
+ * @param ref
+ * @throws Exception
+ */
+ void updateDeliveryCount(Queue queue, MessageReference ref) throws Exception;
+
+ /**
+ * Load the specified queues from persistent storage
+ * @param queues The map of queues to load
+ * @throws Exception
+ */
+ void loadQueues(Map<Long, Queue> queues) throws Exception;
+
+ /**
+ * Get a list of in doubt (prepared) transaction ids
+ * Can only be called in recovery mode
+ * @return the list of ids
+ */
+ List<Xid> getInDoubtXids() throws Exception;
+
+ /**
+ *
+ * @return true if the PersistenceManager is in recovery mode
+ */
+ boolean isInRecoveryMode() throws Exception;
+
+ /**
+ *
+ * @param recoveryMode Set the PersistenceManager in recovery mode
+ */
+ void setInRecoveryMode(boolean recoveryMode);
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/Queue.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/Queue.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/Queue.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+import java.util.List;
+
+
+/**
+ *
+ * A Queue
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface Queue
+{
+ public static final int NUM_PRIORITIES = 10;
+
+ HandleStatus addLast(MessageReference ref);
+
+ HandleStatus addFirst(MessageReference ref);
+
+ void deliver();
+
+ void addConsumer(Consumer consumer);
+
+ boolean removeConsumer(Consumer consumer);
+
+ int getConsumerCount();
+
+ List<MessageReference> list(Filter filter);
+
+ void removeAllReferences();
+
+ long getID();
+
+ Filter getFilter();
+
+ void setFilter(Filter filter);
+
+ int getMessageCount();
+
+ //int getDeliveringCount();
+
+ int getScheduledCount();
+
+ int getMaxSize();
+
+ void setMaxSize(int maxSize);
+
+ DistributionPolicy getDistributionPolicy();
+
+ void setDistributionPolicy(DistributionPolicy policy);
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/QueueStatistics.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/QueueStatistics.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/QueueStatistics.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A QueueStatistics
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface QueueStatistics
+{
+ int getMessageCount();
+
+ int getScheduledCount();
+
+ int getGetDeliveringCount();
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/Transaction.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/Transaction.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/Transaction.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A Transaction
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface Transaction
+{
+ void addSynchronization(TransactionSynchronization sync);
+
+ void prepare(PersistenceManager persistenceManager) throws Exception;
+
+ void commit(PersistenceManager persistenceManager) throws Exception;
+
+ void rollback(PersistenceManager persistenceManager) throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/TransactionStore.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/TransactionStore.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/TransactionStore.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A TransactionStore
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface TransactionStore extends MessagingComponent
+{
+ Transaction getTransaction(Object id);
+
+ void putTransaction(Transaction tx);
+}
Added: trunk/src/main/org/jboss/messaging/newcore/intf/TransactionSynchronization.java
===================================================================
--- trunk/src/main/org/jboss/messaging/newcore/intf/TransactionSynchronization.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/newcore/intf/TransactionSynchronization.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.newcore.intf;
+
+/**
+ *
+ * A TransactionSynchronization
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public interface TransactionSynchronization
+{
+ void beforeCommit() throws Exception;
+
+ void afterCommit() throws Exception;
+
+ void beforeRollback() throws Exception;
+
+ void afterRollback() throws Exception;
+}
Added: trunk/src/main/org/jboss/messaging/test/unit/UnitTestCase.java
===================================================================
--- trunk/src/main/org/jboss/messaging/test/unit/UnitTestCase.java (rev 0)
+++ trunk/src/main/org/jboss/messaging/test/unit/UnitTestCase.java 2007-12-10 19:01:36 UTC (rev 3467)
@@ -0,0 +1,229 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.messaging.test.unit;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.transaction.xa.Xid;
+
+import junit.framework.TestCase;
+
+import org.jboss.jms.tx.MessagingXid;
+import org.jboss.messaging.newcore.impl.MessageImpl;
+import org.jboss.messaging.newcore.intf.Message;
+import org.jboss.messaging.newcore.intf.MessageReference;
+import org.jboss.messaging.newcore.intf.Queue;
+
+/**
+ *
+ * Helper base class for our unit tests
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class UnitTestCase extends TestCase
+{
+ protected void assertByteArraysEquivalent(byte[] bytes1, byte[] bytes2)
+ {
+ if (bytes1.length != bytes2.length)
+ {
+ fail("Byte arrays different sizes bytes1: " + dumpBytes(bytes1) + " bytes2: " + dumpBytes(bytes2));
+ }
+
+ for (int i = 0; i < bytes1.length; i++)
+ {
+ if (bytes1[i] != bytes2[i])
+ {
+ fail("Byte arrays not equivalent: " + dumpBytes(bytes1) + " bytes2: " + dumpBytes(bytes2));
+ }
+ }
+ }
+
+ protected String dumpBytes(byte[] bytes)
+ {
+ StringBuffer buff = new StringBuffer();
+
+ buff.append(System.identityHashCode(bytes) + ", size: " + bytes.length + " [");
+
+ for (int i = 0; i < bytes.length; i++)
+ {
+ buff.append(bytes[i]);
+
+ if (i != bytes.length - 1)
+ {
+ buff.append(", ");
+ }
+ }
+
+ buff.append("]");
+
+ return buff.toString();
+ }
+
+ protected boolean deleteDirectory(File directory)
+ {
+ if (directory.isDirectory())
+ {
+ String[] files = directory.list();
+
+ for (int j = 0; j < files.length; j++)
+ {
+ if (!deleteDirectory(new File(directory, files[j])))
+ {
+ return false;
+ }
+ }
+ }
+
+ return directory.delete();
+ }
+
+ protected void assertRefListsIdenticalRefs(List<MessageReference> l1, List<MessageReference> l2)
+ {
+ if (l1.size() != l2.size())
+ {
+ fail("Lists different sizes: " + l1.size() + ", " + l2.size());
+ }
+
+ Iterator<MessageReference> iter1 = l1.iterator();
+ Iterator<MessageReference> iter2 = l2.iterator();
+
+ while (iter1.hasNext())
+ {
+ MessageReference o1 = iter1.next();
+ MessageReference o2 = iter2.next();
+
+ assertTrue(o1 == o2);
+ }
+ }
+
+ protected void assertRefListsEquivalent(List<MessageReference> l1, List<MessageReference> l2)
+ {
+ if (l1.size() != l2.size())
+ {
+ fail("Lists different sizes: " + l1.size() + ", " + l2.size());
+ }
+
+ Iterator<MessageReference> iter1 = l1.iterator();
+ Iterator<MessageReference> iter2 = l2.iterator();
+
+ while (iter1.hasNext())
+ {
+ MessageReference o1 = iter1.next();
+ MessageReference o2 = iter2.next();
+
+ assertEquals(o1.getMessage().getMessageID(), o2.getMessage().getMessageID());
+
+ assertEquals(o1.getScheduledDeliveryTime(), o2.getScheduledDeliveryTime());
+
+ assertEquals(o1.getDeliveryCount(), o2.getDeliveryCount());
+ }
+ }
+
+ protected Message generateMessage(long id)
+ {
+ Message message = new MessageImpl(id, 0, true, 0, System.currentTimeMillis(), (byte)4);
+
+ byte[] bytes = new byte[1024];
+
+ for (int i = 0; i < 1024; i++)
+ {
+ bytes[i] = (byte)i;
+ }
+
+ message.setPayload(bytes);
+
+ return message;
+ }
+
+ protected MessageReference generateReference(Queue queue, long id)
+ {
+ Message message = generateMessage(id);
+
+ return message.createReference(queue);
+ }
+
+ protected void assertEquivalent(Message msg1, Message msg2)
+ {
+ assertEquals(msg1.getMessageID(), msg2.getMessageID());
+
+ assertEquals(msg1.isReliable(), msg2.isReliable());
+
+ assertEquals(msg1.getExpiration(), msg2.getExpiration());
+
+ assertEquals(msg1.getTimestamp(), msg2.getTimestamp());
+
+ assertEquals(msg1.getPriority(), msg2.getPriority());
+
+ assertEquals(msg1.getType(), msg2.getType());
+
+ if (msg1.getPayload() == null)
+ {
+ assertNull(msg2.getPayload());
+ }
+ else
+ {
+ assertByteArraysEquivalent(msg1.getPayload(), msg2.getPayload());
+ }
+
+ assertMapsEquivalent(msg1.getHeaders(), msg2.getHeaders());
+
+ assertEquals(msg1.getReferences().size(), msg2.getReferences().size());
+
+ for (int i = 0; i < msg1.getReferences().size(); i++)
+ {
+ MessageReference ref1 = msg1.getReferences().get(i);
+
+ MessageReference ref2 = msg2.getReferences().get(i);
+
+ assertEquals(ref1.getScheduledDeliveryTime(), ref2.getScheduledDeliveryTime());
+
+ assertEquals(ref1.getDeliveryCount(), ref2.getDeliveryCount());
+
+ assertEquals(ref1.getQueue(), ref2.getQueue());
+ }
+ }
+
+ protected void assertMapsEquivalent(Map<String, Object> headers1, Map<String, Object> headers2)
+ {
+ assertEquals(headers1.size(), headers2.size());
+
+ for (Map.Entry<String, Object> entry : headers1.entrySet())
+ {
+ assertEquals(entry.getValue(), headers2.get(entry.getKey()));
+ }
+ }
+
+ protected Xid generateXid()
+ {
+ String id = java.util.UUID.randomUUID().toString();
+
+ Xid xid = new MessagingXid("blah".getBytes(), 123, id.getBytes());
+
+ return xid;
+ }
+
+
+}
Modified: trunk/tests/etc/datasource.xml
===================================================================
--- trunk/tests/etc/datasource.xml 2007-12-10 18:44:52 UTC (rev 3466)
+++ trunk/tests/etc/datasource.xml 2007-12-10 19:01:36 UTC (rev 3467)
@@ -7,6 +7,6 @@
</bean>-->
<bean name="jboss.jca:name=DefaultDS,service=DataSourceBinding" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
<property name="url">jdbc:mysql://localhost/messaging</property>
- <property name="user">andy</property>
+ <property name="user">sa</property>
</bean>
</deployment>
\ No newline at end of file
Added: trunk/tests/lib/easymock.jar
===================================================================
(Binary files differ)
Property changes on: trunk/tests/lib/easymock.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
More information about the jboss-cvs-commits
mailing list