[jboss-cvs] JBoss Messaging SVN: r1794 - in trunk: src/main/org/jboss/jms/client src/main/org/jboss/jms/client/container src/main/org/jboss/jms/client/delegate src/main/org/jboss/jms/client/remoting src/main/org/jboss/jms/client/state src/main/org/jboss/jms/delegate src/main/org/jboss/jms/message src/main/org/jboss/jms/server src/main/org/jboss/jms/server/endpoint src/main/org/jboss/jms/server/endpoint/advised src/main/org/jboss/jms/server/remoting src/main/org/jboss/jms/tx tests tests/src/org/jboss/test/messaging/jms tests/src/org/jboss/test/messaging/jms/clustering tests/src/org/jboss/test/messaging/tools/jboss tests/src/org/jboss/test/messaging/tools/jmx/rmi
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Dec 14 14:33:11 EST 2006
Author: timfox
Date: 2006-12-14 14:32:42 -0500 (Thu, 14 Dec 2006)
New Revision: 1794
Added:
trunk/src/main/org/jboss/jms/server/endpoint/Ack.java
trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java
trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java
trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java
trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java
trunk/src/main/org/jboss/jms/tx/ClientTransaction.java
Removed:
trunk/src/main/org/jboss/jms/tx/AckInfo.java
trunk/src/main/org/jboss/jms/tx/TxState.java
Modified:
trunk/src/main/org/jboss/jms/client/Closeable.java
trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java
trunk/src/main/org/jboss/jms/client/JBossSession.java
trunk/src/main/org/jboss/jms/client/container/AsfAspect.java
trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java
trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java
trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java
trunk/src/main/org/jboss/jms/client/container/HAAspect.java
trunk/src/main/org/jboss/jms/client/container/SessionAspect.java
trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java
trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java
trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java
trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java
trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java
trunk/src/main/org/jboss/jms/client/state/SessionState.java
trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java
trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java
trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java
trunk/src/main/org/jboss/jms/message/JBossMessage.java
trunk/src/main/org/jboss/jms/message/MapMessageProxy.java
trunk/src/main/org/jboss/jms/message/MessageProxy.java
trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java
trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java
trunk/src/main/org/jboss/jms/message/TextMessageProxy.java
trunk/src/main/org/jboss/jms/server/ServerPeer.java
trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java
trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java
trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java
trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java
trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java
trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java
trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java
trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java
trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java
trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java
trunk/src/main/org/jboss/jms/tx/ResourceManager.java
trunk/src/main/org/jboss/jms/tx/TransactionRequest.java
trunk/tests/build.xml
trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java
trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java
trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java
trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java
trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java
trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java
Log:
Major refactoring so deliveries are now managed by sessions.
Modified: trunk/src/main/org/jboss/jms/client/Closeable.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/Closeable.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/Closeable.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -47,7 +47,6 @@
* @throws JMSException
*/
void closing() throws JMSException;
-
- boolean isClosed();
-
+
+ boolean isClosed() throws JMSException;
}
Modified: trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -72,37 +72,37 @@
// Attributes ----------------------------------------------------
- protected ConsumerDelegate cons;
+ private ConsumerDelegate cons;
- protected SessionDelegate sess;
+ private SessionDelegate sess;
- protected int consumerID;
+ private int consumerID;
/** The destination this consumer will receive messages from */
- protected Destination destination;
+ private Destination destination;
/** The ServerSessionPool that is implemented by the AS */
- protected ServerSessionPool serverSessionPool;
+ private ServerSessionPool serverSessionPool;
/** The maximum number of messages that a single session will be loaded with. */
- protected int maxMessages;
+ private int maxMessages;
/** Is the ConnectionConsumer closed? */
- protected volatile boolean closed;
+ private volatile boolean closed;
/** The "listening" thread that gets messages from destination and queues
them for delivery to sessions */
- protected Thread internalThread;
+ private Thread internalThread;
/** The thread id */
- protected int id;
+ private int id;
/** The thread id generator */
- protected static SynchronizedInt threadId = new SynchronizedInt(0);
+ private static SynchronizedInt threadId = new SynchronizedInt(0);
- protected Object closeLock = new Object();
+ private int maxDeliveries;
- protected int maxDeliveries;
+ private long channelID;
// Static --------------------------------------------------------
@@ -154,6 +154,8 @@
this.consumerID = state.getConsumerID();
+ this.channelID = state.getChannelId();
+
this.maxDeliveries = state.getMaxDeliveries();
id = threadId.increment();
@@ -302,7 +304,7 @@
for (int i = 0; i < mesList.size(); i++)
{
MessageProxy m = (MessageProxy)mesList.get(i);
- session.addAsfMessage(m, consumerID, cons, maxDeliveries);
+ session.addAsfMessage(m, consumerID, channelID, maxDeliveries);
if (trace) { log.trace("added " + m + " to session"); }
}
Modified: trunk/src/main/org/jboss/jms/client/JBossSession.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/JBossSession.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/JBossSession.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -502,9 +502,9 @@
* This method is used by the JBossConnectionConsumer to load up the session
* with messages to be processed by the session's run() method
*/
- void addAsfMessage(MessageProxy m, int consumerID, ConsumerDelegate cons, int maxDeliveries)
+ void addAsfMessage(MessageProxy m, int consumerID, long channelID, int maxDeliveries)
{
- delegate.addAsfMessage(m, consumerID, cons, maxDeliveries);
+ delegate.addAsfMessage(m, consumerID, channelID, maxDeliveries);
}
// Protected -----------------------------------------------------
Modified: trunk/src/main/org/jboss/jms/client/container/AsfAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/AsfAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/AsfAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -129,7 +129,7 @@
MessageProxy m = (MessageProxy)mi.getArguments()[0];
int theConsumerID = ((Integer)mi.getArguments()[1]).intValue();
- ConsumerDelegate cons = (ConsumerDelegate)mi.getArguments()[2];
+ long channelID = ((Long)mi.getArguments()[2]).longValue();
int maxDeliveries = ((Integer)mi.getArguments()[3]).intValue();
if (m == null)
@@ -140,7 +140,7 @@
AsfMessageHolder holder = new AsfMessageHolder();
holder.msg = m;
holder.consumerID = theConsumerID;
- holder.consumerDelegate = cons;
+ holder.channelID = channelID;
holder.maxDeliveries = maxDeliveries;
msgs.add(holder);
@@ -164,7 +164,8 @@
if (trace) { log.trace("sending " + holder.msg + " to the message listener" ); }
- MessageCallbackHandler.callOnMessage(del, sessionListener, holder.consumerID, false,
+ MessageCallbackHandler.callOnMessage(del, sessionListener, holder.consumerID,
+ holder.channelID, false,
holder.msg, ackMode, holder.maxDeliveries);
}
@@ -184,11 +185,11 @@
// Inner Classes --------------------------------------------------
- protected static class AsfMessageHolder
+ private static class AsfMessageHolder
{
- MessageProxy msg;
- int consumerID;
- ConsumerDelegate consumerDelegate;
- int maxDeliveries;
+ private MessageProxy msg;
+ private int consumerID;
+ private long channelID;
+ private int maxDeliveries;
}
}
Modified: trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -110,11 +110,6 @@
return sb.toString();
}
- public boolean isClosed()
- {
- return state == IN_CLOSE || state == CLOSED;
- }
-
// Interceptor implementation -----------------------------------
public String getName()
@@ -135,6 +130,7 @@
if ("isClosed".equals(methodName))
{
+ //Actually this is badly named, it returns true if it's closing as well as closed
return new Boolean(isClosed());
}
@@ -317,6 +313,11 @@
// Package Private ------------------------------------------------
// Private --------------------------------------------------------
+
+ private boolean isClosed()
+ {
+ return state == IN_CLOSE || state == CLOSED;
+ }
// Inner Classes --------------------------------------------------
Modified: trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -74,6 +74,7 @@
ConsumerState consumerState = (ConsumerState)((DelegateSupport)consumerDelegate).getState();
int serverId = connectionState.getServerID();
int consumerID = consumerState.getConsumerID();
+ long channelID = consumerState.getChannelId();
int prefetchSize = consumerState.getPrefetchSize();
QueuedExecutor sessionExecutor = sessionState.getExecutor();
int maxDeliveries = consumerState.getMaxDeliveries();
@@ -81,12 +82,13 @@
MessageCallbackHandler messageHandler =
new MessageCallbackHandler(isCC, sessionState.getAcknowledgeMode(),
sessionDelegate, consumerDelegate, consumerID,
+ channelID,
prefetchSize, sessionExecutor, maxDeliveries);
sessionState.addCallbackHandler(messageHandler);
CallbackManager cm = connectionState.getRemotingConnection().getCallbackManager();
- cm.registerHandler(serverId, consumerID, messageHandler);
+ cm.registerHandler(consumerID, messageHandler);
consumerState.setMessageCallbackHandler(messageHandler);
@@ -115,7 +117,7 @@
sessionState.removeCallbackHandler(consumerState.getMessageCallbackHandler());
CallbackManager cm = connectionState.getRemotingConnection().getCallbackManager();
- cm.unregisterHandler(connectionState.getServerID(), consumerState.getConsumerID());
+ cm.unregisterHandler(consumerState.getConsumerID());
return res;
}
Modified: trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -65,21 +65,21 @@
{
JBossMessage jbm = new JBossMessage(0);
- return new MessageProxy(jbm, 0);
+ return new MessageProxy(jbm);
}
public Object handleCreateBytesMessage(Invocation invocation) throws Throwable
{
JBossBytesMessage jbm = new JBossBytesMessage(0);
- return new BytesMessageProxy(jbm, 0);
+ return new BytesMessageProxy(jbm);
}
public Object handleCreateMapMessage(Invocation invocation) throws Throwable
{
JBossMapMessage jbm = new JBossMapMessage(0);
- return new MapMessageProxy(jbm, 0);
+ return new MapMessageProxy(jbm);
}
public Object handleCreateObjectMessage(Invocation invocation) throws Throwable
@@ -93,14 +93,14 @@
jbm.setObject((Serializable)mi.getArguments()[0]);
}
- return new ObjectMessageProxy(jbm, 0);
+ return new ObjectMessageProxy(jbm);
}
public Object handleCreateStreamMessage(Invocation invocation) throws Throwable
{
JBossStreamMessage jbm = new JBossStreamMessage(0);
- return new StreamMessageProxy(jbm, 0);
+ return new StreamMessageProxy(jbm);
}
public Object handleCreateTextMessage(Invocation invocation) throws Throwable
@@ -114,7 +114,7 @@
jbm.setText((String)mi.getArguments()[0]);
}
- return new TextMessageProxy(jbm, 0);
+ return new TextMessageProxy(jbm);
}
// Package protected ---------------------------------------------
Modified: trunk/src/main/org/jboss/jms/client/container/HAAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/HAAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/HAAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -23,11 +23,10 @@
package org.jboss.jms.client.container;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.jms.JMSException;
@@ -49,9 +48,11 @@
import org.jboss.jms.client.state.HierarchicalStateSupport;
import org.jboss.jms.client.state.ProducerState;
import org.jboss.jms.client.state.SessionState;
+import org.jboss.jms.delegate.SessionDelegate;
import org.jboss.jms.destination.JBossDestination;
import org.jboss.jms.server.endpoint.CreateConnectionResult;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
+import org.jboss.jms.server.endpoint.DeliveryRecovery;
import org.jboss.jms.tx.ResourceManager;
import org.jboss.logging.Logger;
import org.jboss.remoting.Client;
@@ -340,16 +341,21 @@
// Transfer attributes from newDelegate to failedDelegate
failedConnDelegate.copyAttributes(newConnDelegate);
- int oldServerId = failedState.getServerID();
-
CallbackManager oldCallbackManager = failedState.getRemotingConnection().getCallbackManager();
//We need to update some of the attributes on the state
failedState.copyState(newState);
+
+ //Map of old session id to new session state
+ Map oldNewSessionStateMap = new HashMap();
for(Iterator i = failedState.getChildren().iterator(); i.hasNext(); )
{
SessionState failedSessionState = (SessionState)i.next();
+
+ if (trace) { log.trace("Failed session state has " + failedSessionState.getToAck().size() + " deliveries"); }
+
+ int oldSessionId = failedSessionState.getSessionId();
ClientSessionDelegate failedSessionDelegate =
(ClientSessionDelegate)failedSessionState.getDelegate();
@@ -360,11 +366,15 @@
failedSessionState.isXA());
SessionState newSessionState = (SessionState)newSessionDelegate.getState();
+
+ if (trace) { log.trace("New session state has " + newSessionState.getToAck().size() + " deliveries"); }
+
+ oldNewSessionStateMap.put(new Integer(oldSessionId), failedSessionState);
failedSessionDelegate.copyAttributes(newSessionDelegate);
//We need to update some of the attributes on the state
- newSessionState.copyState(newSessionState);
+ failedSessionState.copyState(newSessionState);
if (trace) { log.trace("replacing session (" + failedSessionDelegate + ") with a new failover session " + newSessionDelegate); }
@@ -373,8 +383,6 @@
// TODO Why is this clone necessary?
children.addAll(failedSessionState.getChildren());
- Set consumerIds = new HashSet();
-
for (Iterator j = children.iterator(); j.hasNext(); )
{
HierarchicalStateSupport sessionChild = (HierarchicalStateSupport)j.next();
@@ -386,48 +394,58 @@
else if (sessionChild instanceof ConsumerState)
{
handleFailoverOnConsumer(failedConnDelegate,
- failedState,
- failedSessionState,
(ConsumerState)sessionChild,
failedSessionDelegate,
- oldServerId,
oldCallbackManager);
-
- // We add the new consumer id to the list of old ids
- consumerIds.add(new Integer(((ConsumerState)sessionChild).getConsumerID()));
}
else if (sessionChild instanceof BrowserState)
{
handleFailoverOnBrowser((BrowserState)sessionChild, newSessionDelegate);
}
}
-
- /* Now we must sent the list of unacked AckInfos to the server - so the consumers
- * delivery lists can be repopulated
- */
+ }
+
+ //First we must tell the resource manager to substitute old session id for new session id
+ //Note we MUST submit the entire mapping in one operation since there may be overlap between
+ //old and new session id, and we don't want to overwrite keys in the map
+
+ failedState.getResourceManager().handleFailover(oldNewSessionStateMap);
+
+ Iterator iter = oldNewSessionStateMap.values().iterator();
+
+ while (iter.hasNext())
+ {
+ SessionState state = (SessionState)iter.next();
+
List ackInfos = null;
-
- if (!failedSessionState.isTransacted() && !failedSessionState.isXA())
+
+ if (!state.isTransacted() && !state.isXA())
{
- /*
- Now we remove any unacked np messages - this is because we don't want to ack them
- since the server won't know about them and will barf
- */
+ //Now we remove any unacked np messages - this is because we don't want to ack them
+ //since the server won't know about them and will barf
+
+ Iterator iter2 = state.getToAck().iterator();
+
+ if (trace) { log.trace("Removing any np deliveries"); }
- Iterator iter = newSessionState.getToAck().iterator();
-
- while (iter.hasNext())
+ while (iter2.hasNext())
{
- AckInfo info = (AckInfo)iter.next();
+ DeliveryInfo info = (DeliveryInfo)iter2.next();
- if (!info.getMessage().getMessage().isReliable())
+ if (!info.getMessageProxy().getMessage().isReliable())
{
- iter.remove();
+ iter2.remove();
+
+ if (trace) { log.trace("Removed np delivery: " + info.getDeliveryId()); }
}
}
+
+ if (trace) { log.trace("Session is not transacted, retrieving deliveries from session state"); }
//Get the ack infos from the list in the session state
- ackInfos = failedSessionState.getToAck();
+ ackInfos = state.getToAck();
+
+ if (trace) { log.trace("Retrieved " + ackInfos.size() + " deliveries"); }
}
else
{
@@ -435,24 +453,36 @@
//btw we have kept the old resource manager
ResourceManager rm = failedState.getResourceManager();
- // Remove any non persistent acks - so server doesn't barf on commit
-
- rm.removeNonPersistentAcks(consumerIds);
-
- ackInfos = rm.getAckInfosForConsumerIds(consumerIds);
+ ackInfos = rm.getDeliveriesForSession(state.getSessionId());
}
if (!ackInfos.isEmpty())
+ {
+ SessionDelegate newDelegate = (SessionDelegate)state.getDelegate();
+
+ List recoveryInfos = new ArrayList();
+
+ for (Iterator iter2 = ackInfos.iterator(); iter2.hasNext(); )
+ {
+ DeliveryInfo info = (DeliveryInfo)iter2.next();
+
+ DeliveryRecovery recInfo =
+ new DeliveryRecovery(info.getMessageProxy().getDeliveryId(),
+ info.getMessageProxy().getMessage().getMessageID(),
+ info.getChannelId());
+
+ recoveryInfos.add(recInfo);
+ }
+
+ if (trace) { log.trace(this + " sending delivery recovery info: " + recoveryInfos); }
+ newDelegate.recoverDeliveries(recoveryInfos);
+ }
+ else
{
- log.info("Sending " + ackInfos.size() + " unacked");
- newSessionDelegate.sendUnackedAckInfos(ackInfos);
+ if (trace) { log.trace(this + " no delivery recovery info to send"); }
}
}
- //TODO
- //If the session had consumers which are now closed then there is no way to recreate them on the server
- //we need to store with session id
-
// We must not start the connection until the end
if (failedState.isStarted())
{
@@ -463,11 +493,8 @@
}
private void handleFailoverOnConsumer(ClientConnectionDelegate failedConnectionDelegate,
- ConnectionState failedConnectionState,
- SessionState failedSessionState,
ConsumerState failedConsumerState,
ClientSessionDelegate failedSessionDelegate,
- int oldServerID,
CallbackManager oldCallbackManager)
throws JMSException
{
@@ -498,19 +525,21 @@
// Update attributes on the old state
failedConsumerState.copyState(newState);
- if (failedSessionState.isTransacted() || failedSessionState.isXA())
- {
- // Replace the old consumer id with the new consumer id
+// if (failedSessionState.isTransacted() || failedSessionState.isXA())
+// {
+// // Replace the old consumer id with the new consumer id
+//
+// ResourceManager rm = failedConnectionState.getResourceManager();
+//
+// todo - we need to replace the sesion id
+//
+// rm.handleFailover(oldConsumerID, failedConsumerState.getConsumerID());
+// }
- ResourceManager rm = failedConnectionState.getResourceManager();
-
- rm.handleFailover(oldConsumerID, failedConsumerState.getConsumerID());
- }
-
// We need to re-use the existing message callback handler
MessageCallbackHandler oldHandler =
- oldCallbackManager.unregisterHandler(oldServerID, oldConsumerID);
+ oldCallbackManager.unregisterHandler(oldConsumerID);
ConnectionState newConnectionState = (ConnectionState)failedConnectionDelegate.getState();
@@ -519,7 +548,7 @@
// Remove the new handler
MessageCallbackHandler newHandler = newCallbackManager.
- unregisterHandler(newConnectionState.getServerID(), newState.getConsumerID());
+ unregisterHandler(newState.getConsumerID());
log.debug("New handler is " + System.identityHashCode(newHandler));
@@ -528,8 +557,7 @@
//Now we re-register the old handler with the new callback manager
- newCallbackManager.registerHandler(newConnectionState.getServerID(),
- newState.getConsumerID(),
+ newCallbackManager.registerHandler(newState.getConsumerID(),
oldHandler);
// We don't need to add the handler to the session state since it is already there - we
Modified: trunk/src/main/org/jboss/jms/client/container/SessionAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/SessionAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/SessionAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -36,7 +36,9 @@
import org.jboss.jms.client.state.SessionState;
import org.jboss.jms.delegate.SessionDelegate;
import org.jboss.jms.message.MessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.Cancel;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
import org.jboss.logging.Logger;
import org.jboss.messaging.util.Util;
@@ -79,15 +81,16 @@
List cancels = new ArrayList();
for(Iterator i = state.getToAck().iterator(); i.hasNext(); )
{
- AckInfo ack = (AckInfo)i.next();
+ DeliveryInfo ack = (DeliveryInfo)i.next();
if (ackMode == Session.AUTO_ACKNOWLEDGE ||
ackMode == Session.DUPS_OK_ACKNOWLEDGE)
{
- acks.add(ack);
+ acks.add(new DefaultAck(ack.getMessageProxy().getDeliveryId()));
}
else
{
- cancels.add(ack);
+ Cancel cancel = new Cancel(ack.getMessageProxy().getDeliveryId(), ack.getMessageProxy().getDeliveryCount());
+ cancels.add(cancel);
}
i.remove();
}
@@ -104,6 +107,7 @@
}
if (!cancels.isEmpty())
{
+ log.info("Calling canceldeliveries: " + cancels.size());
del.cancelDeliveries(cancels);
}
@@ -136,25 +140,26 @@
state.getCurrentTxId() == null)
{
// We collect acknowledgments (and not transact them) for CLIENT, AUTO and DUPS_OK, and
- // also for XA sessions not enrolled in a global transaction.
-
- SessionDelegate del = (SessionDelegate)mi.getTargetObject();
-
+ // also for XA sessions not enlisted in a global transaction.
+
// We store the ack in a list for later acknowledgement or recovery
Object[] args = mi.getArguments();
- MessageProxy mp = (MessageProxy)args[0];
- int consumerID = ((Integer)args[1]).intValue();
- AckInfo info = new AckInfo(mp, consumerID);
-
+ DeliveryInfo info = (DeliveryInfo)args[0];
+
state.getToAck().add(info);
- if (trace) { log.trace("ack mode is " + Util.acknowledgmentModeToString(ackMode)+ ", acknowledged on " + del); }
+ if (trace)
+ {
+ SessionDelegate del = (SessionDelegate)mi.getTargetObject();
+ log.trace("ack mode is " + Util.acknowledgmentModeToString(ackMode)+ ", acknowledged on " + del);
+ }
}
return invocation.invokeNext();
}
+ /* Used for client acknowledge */
public Object handleAcknowledgeAll(Invocation invocation) throws Throwable
{
MethodInvocation mi = (MethodInvocation)invocation;
@@ -187,7 +192,7 @@
if (ackMode == Session.AUTO_ACKNOWLEDGE ||
ackMode == Session.DUPS_OK_ACKNOWLEDGE ||
- ackMode != Session.CLIENT_ACKNOWLEDGE && state.getCurrentTxId() == null)
+ (ackMode != Session.CLIENT_ACKNOWLEDGE && state.getCurrentTxId() == null))
{
// We acknowledge immediately on a non-transacted session that does not want to
// CLIENT_ACKNOWLEDGE, or an XA session not enrolled in a global transaction.
@@ -207,16 +212,21 @@
"There are " + acks.size());
}
- AckInfo ack = (AckInfo)acks.get(0);
+ DeliveryInfo ack = (DeliveryInfo)acks.get(0);
if (cancel)
{
- sd.cancelDeliveries(acks);
+ List cancels = new ArrayList();
+ Cancel c = new Cancel(ack.getMessageProxy().getDeliveryId(), ack.getMessageProxy().getDeliveryCount());
+ cancels.add(c);
+ sd.cancelDeliveries(cancels);
}
else
{
sd.acknowledge(ack);
}
+
+ //TODO we can optimise this for the auto_ack case (i.e. not store in list and have to clear each time)
state.getToAck().clear();
}
else
@@ -302,16 +312,17 @@
// Need to be recovered in reverse order.
for (int i = toRedeliver.size() - 1; i >= 0; i--)
{
- AckInfo info = (AckInfo)toRedeliver.get(i);
- MessageProxy proxy = info.getMessage();
+ DeliveryInfo info = (DeliveryInfo)toRedeliver.get(i);
+ MessageProxy proxy = info.getMessageProxy();
- MessageCallbackHandler handler = state.getCallbackHandler(info.getConsumerID());
+ MessageCallbackHandler handler = state.getCallbackHandler(info.getConsumerId());
if (handler == null)
{
// This is ok. The original consumer has closed, this message wil get cancelled back
// to the channel.
- toCancel.addFirst(info);
+ Cancel cancel = new Cancel(info.getMessageProxy().getDeliveryId(), info.getMessageProxy().getDeliveryCount());
+ toCancel.addFirst(cancel);
}
else
{
Modified: trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -28,6 +28,7 @@
import org.jboss.jms.client.delegate.ClientConnectionDelegate;
import org.jboss.jms.client.delegate.ClientConsumerDelegate;
import org.jboss.jms.client.delegate.ClientProducerDelegate;
+import org.jboss.jms.client.delegate.ClientSessionDelegate;
import org.jboss.jms.client.delegate.DelegateSupport;
import org.jboss.jms.client.remoting.JMSRemotingConnection;
import org.jboss.jms.client.remoting.ConsolidatedRemotingConnectionListener;
@@ -40,7 +41,6 @@
import org.jboss.jms.delegate.BrowserDelegate;
import org.jboss.jms.delegate.ConnectionFactoryDelegate;
import org.jboss.jms.delegate.ProducerDelegate;
-import org.jboss.jms.delegate.SessionDelegate;
import org.jboss.jms.destination.JBossDestination;
import org.jboss.jms.message.MessageIdGenerator;
import org.jboss.jms.message.MessageIdGeneratorFactory;
@@ -132,7 +132,7 @@
public Object handleCreateSessionDelegate(Invocation invocation) throws Throwable
{
- SessionDelegate sessionDelegate = (SessionDelegate)invocation.invokeNext();
+ ClientSessionDelegate sessionDelegate = (ClientSessionDelegate)invocation.invokeNext();
DelegateSupport delegate = (DelegateSupport)sessionDelegate;
delegate.init();
Modified: trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -32,8 +32,8 @@
import org.jboss.jms.client.state.HierarchicalState;
import org.jboss.jms.client.state.SessionState;
import org.jboss.jms.delegate.ConnectionDelegate;
-import org.jboss.jms.message.MessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
import org.jboss.jms.tx.LocalTx;
import org.jboss.jms.tx.ResourceManager;
import org.jboss.logging.Logger;
@@ -164,7 +164,7 @@
if (trace) { log.trace("sending message " + m + " transactionally, queueing on resource manager"); }
- connState.getResourceManager().addMessage(txID, m);
+ connState.getResourceManager().addMessage(txID, state.getSessionId(), (JBossMessage)m);
// ... and we don't invoke any further interceptors in the stack
return null;
@@ -185,16 +185,16 @@
// the session is non-XA and transacted, or XA and enrolled in a global transaction. An
// XA session that has not been enrolled in a global transaction behaves as a
// non-transacted session.
+
+ MethodInvocation mi = (MethodInvocation)invocation;
+
+ DeliveryInfo info = (DeliveryInfo)mi.getArguments()[0];
- MethodInvocation mi = (MethodInvocation)invocation;
- MessageProxy proxy = (MessageProxy)mi.getArguments()[0];
- int consumerID = ((Integer)mi.getArguments()[1]).intValue();
- AckInfo info = new AckInfo(proxy, consumerID);
ConnectionState connState = (ConnectionState)state.getParent();
if (trace) { log.trace("sending acknowlegment transactionally, queueing on resource manager"); }
- connState.getResourceManager().addAck(txID, info);
+ connState.getResourceManager().addAck(txID, state.getSessionId(), info);
}
return null;
Modified: trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -43,7 +43,8 @@
import org.jboss.jms.message.ObjectMessageProxy;
import org.jboss.jms.message.StreamMessageProxy;
import org.jboss.jms.message.TextMessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
import org.jboss.remoting.Client;
/**
@@ -111,7 +112,7 @@
* This invocation should either be handled by the client-side interceptor chain or by the
* server-side endpoint.
*/
- public void acknowledge(AckInfo ackInfo) throws JMSException
+ public void acknowledge(Ack ack) throws JMSException
{
throw new IllegalStateException("This invocation should not be handled here!");
}
@@ -120,7 +121,7 @@
* This invocation should either be handled by the client-side interceptor chain or by the
* server-side endpoint.
*/
- public void acknowledgeBatch(List ackInfos) throws JMSException
+ public void acknowledgeBatch(List acks) throws JMSException
{
throw new IllegalStateException("This invocation should not be handled here!");
}
@@ -313,7 +314,7 @@
* This invocation should either be handled by the client-side interceptor chain or by the
* server-side endpoint.
*/
- public void preDeliver(MessageProxy proxy, int consumerID) throws JMSException
+ public void preDeliver(DeliveryInfo deliveryInfo) throws JMSException
{
throw new IllegalStateException("This invocation should not be handled here!");
}
@@ -404,8 +405,7 @@
* This invocation should either be handled by the client-side interceptor chain or by the
* server-side endpoint.
*/
- public void addAsfMessage(MessageProxy m, int consumerID,
- ConsumerDelegate cons, int maxDeliveries)
+ public void addAsfMessage(MessageProxy m, int consumerID, long channelId, int maxDeliveries)
{
throw new IllegalStateException("This invocation should not be handled here!");
}
@@ -432,7 +432,7 @@
* This invocation should either be handled by the client-side interceptor chain or by the
* server-side endpoint.
*/
- public void sendUnackedAckInfos(List ackInfos) throws JMSException
+ public void recoverDeliveries(List ackInfos) throws JMSException
{
throw new IllegalStateException("This invocation should not be handled here!");
}
Modified: trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -40,6 +40,9 @@
* The CallbackManager is an InvocationHandler used for handling callbacks to message consumers.
* The callback is received and dispatched off to the relevant consumer.
*
+ * There is one instance of this class per remoting connection - which is to a unique server - therefore
+ * there is no need to add the server id to the key when doing look ups
+ *
* @author <a href="tim.fox at jboss.com">Tim Fox</a>
* @author <a href="ovidiu at jboss.org">Ovidiu Feodorov</a>
* @version 1.1
@@ -76,15 +79,13 @@
{
MessagingMarshallable mm = (MessagingMarshallable)callback.getParameter();
ClientDelivery dr = (ClientDelivery)mm.getLoad();
- Long lookup = computeLookup(dr.getServerId(), dr.getConsumerId());
List msgs = dr.getMessages();
- MessageCallbackHandler handler = (MessageCallbackHandler)callbackHandlers.get(lookup);
+ MessageCallbackHandler handler = (MessageCallbackHandler)callbackHandlers.get(new Integer(dr.getConsumerId()));
if (handler == null)
{
- throw new IllegalStateException("Cannot find handler for consumer: " + dr.getConsumerId() +
- " and server " + dr.getServerId());
+ throw new IllegalStateException("Cannot find handler for consumer: " + dr.getConsumerId());
}
handler.handleMessage(msgs);
@@ -92,18 +93,14 @@
// Public --------------------------------------------------------
- public void registerHandler(int serverID, int consumerID, MessageCallbackHandler handler)
+ public void registerHandler(int consumerID, MessageCallbackHandler handler)
{
- Long lookup = computeLookup(serverID, consumerID);
-
- callbackHandlers.put(lookup, handler);
+ callbackHandlers.put(new Integer(consumerID), handler);
}
- public MessageCallbackHandler unregisterHandler(int serverID, int consumerID)
+ public MessageCallbackHandler unregisterHandler(int consumerID)
{
- Long lookup = computeLookup(serverID, consumerID);
-
- return (MessageCallbackHandler)callbackHandlers.remove(lookup);
+ return (MessageCallbackHandler)callbackHandlers.remove(new Integer(consumerID));
}
// Package protected ---------------------------------------------
@@ -112,17 +109,6 @@
// Private -------------------------------------------------------
- private Long computeLookup(int serverID, int consumerID)
- {
- long id1 = serverID;
-
- id1 <<= 32;
-
- long lookup = id1 | consumerID;
-
- return new Long(lookup);
- }
-
// Inner classes -------------------------------------------------
}
Modified: trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -34,9 +34,9 @@
import org.jboss.jms.delegate.ConsumerDelegate;
import org.jboss.jms.delegate.SessionDelegate;
import org.jboss.jms.message.MessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.Cancel;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
import org.jboss.logging.Logger;
-import org.jboss.messaging.core.Message;
import org.jboss.messaging.util.Future;
import org.jboss.remoting.callback.HandleCallbackException;
@@ -68,13 +68,14 @@
public static void callOnMessage(SessionDelegate sess,
MessageListener listener,
int consumerID,
+ long channelID,
boolean isConnectionConsumer,
MessageProxy m,
int ackMode,
int maxDeliveries)
throws JMSException
{
- preDeliver(sess, consumerID, m, isConnectionConsumer);
+ preDeliver(sess, consumerID, channelID, m, isConnectionConsumer);
int tries = 0;
@@ -141,6 +142,7 @@
protected static void preDeliver(SessionDelegate sess,
int consumerID,
+ long channelID,
MessageProxy m,
boolean isConnectionConsumer)
throws JMSException
@@ -149,7 +151,7 @@
// add anything to the tx for this session.
if (!isConnectionConsumer)
{
- sess.preDeliver(m, consumerID);
+ sess.preDeliver(new DeliveryInfo(m, consumerID, channelID));
}
}
@@ -181,11 +183,13 @@
private QueuedExecutor sessionExecutor;
private boolean listenerRunning;
private int maxDeliveries;
+ private long channelID;
// Constructors --------------------------------------------------
public MessageCallbackHandler(boolean isCC, int ackMode,
SessionDelegate sess, ConsumerDelegate cons, int consumerID,
+ long channelID,
int bufferSize, QueuedExecutor sessionExecutor,
int maxDeliveries)
{
@@ -201,6 +205,7 @@
this.sessionDelegate = sess;
this.consumerDelegate = cons;
this.consumerID = consumerID;
+ this.channelID = channelID;
this.serverSending = true;
mainLock = new Object();
this.sessionExecutor = sessionExecutor;
@@ -281,7 +286,7 @@
}
}
}
-
+
public void close() throws JMSException
{
synchronized (mainLock)
@@ -321,16 +326,16 @@
// have actually been delivered (unlike these) and we may want to acknowledge them
// later, after this consumer has been closed
- List ackInfos = new ArrayList();
+ List cancels = new ArrayList();
for(Iterator i = buffer.iterator(); i.hasNext();)
{
MessageProxy mp = (MessageProxy)i.next();
- AckInfo ack = new AckInfo(mp, consumerID);
- ackInfos.add(ack);
+ Cancel ack = new Cancel(mp.getDeliveryId(), mp.getDeliveryCount());
+ cancels.add(ack);
}
- sessionDelegate.cancelDeliveries(ackInfos);
+ sessionDelegate.cancelDeliveries(cancels);
buffer.clear();
}
@@ -445,7 +450,7 @@
// If message is expired we still call pre and post deliver. This makes sure the
// message is acknowledged so it gets removed from the queue/subscription.
- preDeliver(sessionDelegate, consumerID, m, isConnectionConsumer);
+ preDeliver(sessionDelegate, consumerID, channelID, m, isConnectionConsumer);
postDeliver(sessionDelegate, isConnectionConsumer, false);
@@ -726,7 +731,7 @@
{
try
{
- callOnMessage(sessionDelegate, listener, consumerID, false, mp, ackMode, maxDeliveries);
+ callOnMessage(sessionDelegate, listener, consumerID, channelID, false, mp, ackMode, maxDeliveries);
}
catch (JMSException e)
{
Modified: trunk/src/main/org/jboss/jms/client/state/SessionState.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/state/SessionState.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/state/SessionState.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -27,8 +27,9 @@
import java.util.List;
import java.util.Map;
+import org.jboss.jms.client.delegate.ClientSessionDelegate;
+import org.jboss.jms.client.delegate.DelegateSupport;
import org.jboss.jms.client.remoting.MessageCallbackHandler;
-import org.jboss.jms.client.delegate.DelegateSupport;
import org.jboss.jms.delegate.SessionDelegate;
import org.jboss.jms.server.Version;
import org.jboss.jms.tx.MessagingXAResource;
@@ -50,6 +51,8 @@
{
protected static Logger log = Logger.getLogger(SessionState.class);
+ private int sessionId;
+
private int acknowledgeMode;
private boolean transacted;
@@ -74,10 +77,13 @@
private Map callbackHandlers;
- public SessionState(ConnectionState parent, SessionDelegate delegate,
- boolean transacted, int ackMode, boolean xa)
+ public SessionState(ConnectionState parent, ClientSessionDelegate delegate,
+ boolean transacted, int ackMode, boolean xa)
{
super(parent, (DelegateSupport)delegate);
+
+ this.sessionId = delegate.getID();
+
children = new HashSet();
this.acknowledgeMode = ackMode;
this.transacted = transacted;
@@ -206,12 +212,18 @@
return new ArrayList(callbackHandlers.values());
}
+ public int getSessionId()
+ {
+ return sessionId;
+ }
+
// When failing over a session, we keep the old session's state but there are certain fields
// we need to update
public void copyState(SessionState newState)
{
- //Actually only one field
this.delegate = newState.delegate;
+
+ this.sessionId = newState.sessionId;
}
}
Modified: trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -53,10 +53,4 @@
String messageSelector,
ServerSessionPool sessionPool,
int maxMessages) throws JMSException;
-
- /**
- * Reconnects the current connection hierarchy using newConnection's properties.
- */
- //void failOver(ConnectionDelegate newConnection);
-
}
Modified: trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -35,6 +35,7 @@
import org.jboss.jms.message.ObjectMessageProxy;
import org.jboss.jms.message.StreamMessageProxy;
import org.jboss.jms.message.TextMessageProxy;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
import org.jboss.jms.server.endpoint.SessionEndpoint;
/**
@@ -65,7 +66,7 @@
TextMessageProxy createTextMessage(String text) throws JMSException;
- void preDeliver(MessageProxy proxy, int consumerID) throws JMSException;
+ void preDeliver(DeliveryInfo deliveryInfo) throws JMSException;
void postDeliver(boolean cancel) throws JMSException;
@@ -77,7 +78,7 @@
XAResource getXAResource();
- void addAsfMessage(MessageProxy m, int consumerID, ConsumerDelegate cons, int maxDeliveries);
+ void addAsfMessage(MessageProxy m, int consumerID, long channelID, int maxDeliveries);
boolean getTransacted();
@@ -89,7 +90,7 @@
void recover() throws JMSException;
- void redeliver(List ackInfos) throws JMSException;
+ void redeliver(List deliveryInfos) throws JMSException;
ProducerDelegate createProducerDelegate(JBossDestination destination) throws JMSException;
Modified: trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -38,10 +38,15 @@
{
private static final long serialVersionUID = -9121097962625801946L;
- public BytesMessageProxy(JBossBytesMessage message, int deliveryCount)
+ public BytesMessageProxy(long deliveryId, JBossBytesMessage message, int deliveryCount)
{
- super(message, deliveryCount);
+ super(deliveryId, message, deliveryCount);
}
+
+ public BytesMessageProxy(JBossBytesMessage message)
+ {
+ super(message);
+ }
public long getBodyLength() throws JMSException
{
Modified: trunk/src/main/org/jboss/jms/message/JBossMessage.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/JBossMessage.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/JBossMessage.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -104,33 +104,33 @@
reservedIdentifiers.add("ESCAPE");
}
- public static MessageProxy createThinDelegate(JBossMessage m, int deliveryCount)
+ public static MessageProxy createThinDelegate(long deliveryId, JBossMessage m, int deliveryCount)
{
MessageProxy del;
if (m instanceof BytesMessage)
{
- del = new BytesMessageProxy((JBossBytesMessage)m, deliveryCount);
+ del = new BytesMessageProxy(deliveryId, (JBossBytesMessage)m, deliveryCount);
}
else if (m instanceof MapMessage)
{
- del = new MapMessageProxy((JBossMapMessage)m, deliveryCount);
+ del = new MapMessageProxy(deliveryId, (JBossMapMessage)m, deliveryCount);
}
else if (m instanceof ObjectMessage)
{
- del = new ObjectMessageProxy((JBossObjectMessage)m, deliveryCount);
+ del = new ObjectMessageProxy(deliveryId, (JBossObjectMessage)m, deliveryCount);
}
else if (m instanceof StreamMessage)
{
- del = new StreamMessageProxy((JBossStreamMessage)m, deliveryCount);
+ del = new StreamMessageProxy(deliveryId, (JBossStreamMessage)m, deliveryCount);
}
else if (m instanceof TextMessage)
{
- del = new TextMessageProxy((JBossTextMessage)m, deliveryCount);
+ del = new TextMessageProxy(deliveryId, (JBossTextMessage)m, deliveryCount);
}
else
{
- del = new MessageProxy(m, deliveryCount);
+ del = new MessageProxy(deliveryId, m, deliveryCount);
}
return del;
Modified: trunk/src/main/org/jboss/jms/message/MapMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/MapMessageProxy.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/MapMessageProxy.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -39,11 +39,16 @@
{
private static final long serialVersionUID = 6953530870351885569L;
- public MapMessageProxy(JBossMapMessage message, int deliveryCount)
+ public MapMessageProxy(long deliveryId, JBossMapMessage message, int deliveryCount)
{
- super(message, deliveryCount);
+ super(deliveryId, message, deliveryCount);
}
+ public MapMessageProxy(JBossMapMessage message)
+ {
+ super(message);
+ }
+
public boolean getBoolean(String name) throws JMSException
{
return ((MapMessage)message).getBoolean(name);
Modified: trunk/src/main/org/jboss/jms/message/MessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/MessageProxy.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/MessageProxy.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -65,30 +65,46 @@
// Attributes ----------------------------------------------------
- protected JBossMessage message;
-
- protected transient SessionDelegate delegate;
+ private transient SessionDelegate delegate;
- protected transient boolean cc;
- protected transient boolean messageCopied;
- protected transient boolean propertiesCopied;
- protected transient boolean bodyCopied;
+ private transient boolean cc;
+
+ private transient boolean messageCopied;
+
+ private transient boolean propertiesCopied;
+
+ private transient boolean bodyCopied;
- protected transient int state;
+ private transient int state;
- protected transient boolean propertiesReadOnly;
+ private transient boolean propertiesReadOnly;
+
+ private int deliveryCount;
+
+ private long deliveryId;
+
protected transient boolean bodyReadOnly;
+
+ protected JBossMessage message;
- protected int deliveryCount;
// Constructors --------------------------------------------------
public MessageProxy()
{
}
+
+ public MessageProxy(JBossMessage message)
+ {
+ this.deliveryId = -1;
+ this.message = message;
+ this.state = STATE_NEW;
+ this.deliveryCount = 0;
+ }
- public MessageProxy(JBossMessage message, int deliveryCount)
+ public MessageProxy(long deliveryId, JBossMessage message, int deliveryCount)
{
+ this.deliveryId = deliveryId;
this.message = message;
this.state = STATE_NEW;
this.deliveryCount = deliveryCount;
@@ -433,6 +449,11 @@
{
this.deliveryCount++;
}
+
+ public long getDeliveryId()
+ {
+ return deliveryId;
+ }
public String toString()
{
Modified: trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -39,10 +39,15 @@
{
private static final long serialVersionUID = 8797295997477962825L;
- public ObjectMessageProxy(JBossObjectMessage message, int deliveryCount)
+ public ObjectMessageProxy(long deliveryId, JBossObjectMessage message, int deliveryCount)
{
- super(message, deliveryCount);
+ super(deliveryId, message, deliveryCount);
}
+
+ public ObjectMessageProxy(JBossObjectMessage message)
+ {
+ super(message);
+ }
public void setObject(Serializable object) throws JMSException
{
Modified: trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -38,10 +38,15 @@
{
private static final long serialVersionUID = 856367553964704474L;
- public StreamMessageProxy(JBossStreamMessage message, int deliveryCount)
+ public StreamMessageProxy(long deliveryId, JBossStreamMessage message, int deliveryCount)
{
- super(message, deliveryCount);
+ super(deliveryId, message, deliveryCount);
}
+
+ public StreamMessageProxy(JBossStreamMessage message)
+ {
+ super(message);
+ }
public boolean readBoolean() throws JMSException
{
Modified: trunk/src/main/org/jboss/jms/message/TextMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/TextMessageProxy.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/TextMessageProxy.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -34,14 +34,18 @@
*/
public class TextMessageProxy extends MessageProxy implements TextMessage
{
-
private static final long serialVersionUID = -3530143417050205123L;
- public TextMessageProxy(JBossTextMessage message, int deliveryCount)
+ public TextMessageProxy(long deliveryId, JBossTextMessage message, int deliveryCount)
{
- super(message, deliveryCount);
+ super(deliveryId, message, deliveryCount);
}
+ public TextMessageProxy(JBossTextMessage message)
+ {
+ super(message);
+ }
+
public void setText(String string) throws JMSException
{
if (bodyReadOnly)
Modified: trunk/src/main/org/jboss/jms/server/ServerPeer.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/ServerPeer.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/ServerPeer.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -37,10 +37,9 @@
import org.jboss.jms.server.connectionfactory.ConnectionFactoryJNDIMapper;
import org.jboss.jms.server.connectionmanager.SimpleConnectionManager;
import org.jboss.jms.server.connectormanager.SimpleConnectorManager;
-import org.jboss.jms.server.endpoint.ServerConsumerEndpoint;
import org.jboss.jms.server.plugin.contract.JMSUserManager;
-import org.jboss.jms.server.remoting.JMSWireFormat;
import org.jboss.jms.server.remoting.JMSServerInvocationHandler;
+import org.jboss.jms.server.remoting.JMSWireFormat;
import org.jboss.jms.server.security.SecurityMetadataStore;
import org.jboss.jms.util.ExceptionUtil;
import org.jboss.logging.Logger;
@@ -54,20 +53,18 @@
import org.jboss.messaging.core.plugin.contract.PostOffice;
import org.jboss.messaging.core.plugin.contract.ReplicationListener;
import org.jboss.messaging.core.plugin.contract.Replicator;
+import org.jboss.messaging.core.plugin.postoffice.Binding;
import org.jboss.messaging.core.plugin.postoffice.cluster.DefaultClusteredPostOffice;
import org.jboss.messaging.core.plugin.postoffice.cluster.FailoverStatus;
-import org.jboss.messaging.core.plugin.postoffice.Binding;
import org.jboss.messaging.core.tx.TransactionRepository;
import org.jboss.messaging.util.Util;
import org.jboss.mx.loading.UnifiedClassLoader3;
-import org.jboss.remoting.marshal.MarshalFactory;
import org.jboss.remoting.ServerInvocationHandler;
+import org.jboss.remoting.marshal.MarshalFactory;
import org.jboss.system.ServiceCreator;
import org.jboss.system.ServiceMBeanSupport;
import org.w3c.dom.Element;
-import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
-
/**
* A JMS server peer.
*
@@ -146,14 +143,6 @@
private JMSServerInvocationHandler handler;
- // We keep a map of consumers to prevent us to recurse through the attached session in order to
- // find the ServerConsumerDelegate so we can acknowledge the message. Originally, this map was
- // maintained per-connection, but with the http://jira.jboss.org/jira/browse/JBMESSAGING-211 bug
- // we shared it among connections, so a transaction submitted on the "wrong" connection can
- // still succeed. For more details, see the JIRA issue.
-
- private Map consumers;
-
// Constructors --------------------------------------------------
public ServerPeer(int serverPeerID,
@@ -167,8 +156,6 @@
// Some wired components need to be started here
securityStore = new SecurityMetadataStore();
- consumers = new ConcurrentReaderHashMap();
-
version = Version.instance();
failoverStatusLock = new Object();
@@ -709,23 +696,6 @@
return objectIDSequence++;
}
- public ServerConsumerEndpoint putConsumerEndpoint(int consumerID, ServerConsumerEndpoint c)
- {
- log.debug(this + " caching consumer " + consumerID);
- return (ServerConsumerEndpoint)consumers.put(new Integer(consumerID), c);
- }
-
- public ServerConsumerEndpoint getConsumerEndpoint(int consumerID)
- {
- return (ServerConsumerEndpoint)consumers.get(new Integer(consumerID));
- }
-
- public ServerConsumerEndpoint removeConsumerEndpoint(Integer consumerID)
- {
- log.debug(this + " removing consumer " + consumerID + " from the cache");
- return (ServerConsumerEndpoint)consumers.remove(consumerID);
- }
-
public QueuedExecutorPool getQueuedExecutorPool()
{
return queuedExecutorPool;
Added: trunk/src/main/org/jboss/jms/server/endpoint/Ack.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/Ack.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/Ack.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -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.jms.server.endpoint;
+
+/**
+ * A Ack
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public interface Ack
+{
+ long getDeliveryId();
+}
Added: trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,105 @@
+/*
+ * 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.jms.server.endpoint;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
+import org.jboss.messaging.util.Streamable;
+
+/**
+ *
+ * A Cancel.
+ *
+ * Used to send a cancel (NACK) to the server
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class Cancel implements Streamable
+{
+ // Constants -----------------------------------------------------
+
+ // Attributes ----------------------------------------------------
+
+ private long deliveryId;
+
+ private int deliveryCount;
+
+ // Static --------------------------------------------------------
+
+ // Constructors --------------------------------------------------
+
+ public Cancel()
+ {
+ }
+
+ public Cancel(long deliveryId, int deliveryCount)
+ {
+ this.deliveryId = deliveryId;
+
+ this.deliveryCount = deliveryCount;
+ }
+
+ // Public --------------------------------------------------------
+
+ public long getDeliveryId()
+ {
+ return deliveryId;
+ }
+
+ public int getDeliveryCount()
+ {
+ return deliveryCount;
+ }
+
+ // Streamable implementation -------------------------------------
+
+ public void read(DataInputStream in) throws Exception
+ {
+ deliveryId = in.readLong();
+
+ deliveryCount = in.readInt();
+ }
+
+ public void write(DataOutputStream out) throws Exception
+ {
+ out.writeLong(deliveryId);
+
+ out.writeInt(deliveryCount);
+ }
+
+ // Class YYY overrides -------------------------------------------
+
+ // Protected -----------------------------------------------------
+
+ // Package Private -----------------------------------------------
+
+ // Private -------------------------------------------------------
+
+ // Inner Classes -------------------------------------------------
+
+}
+
Modified: trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -37,6 +37,9 @@
* A ClientDelivery
* Encapsulates a delivery of some messages to a client consumer
*
+ * There is no need to specify the server id since the client side CallbackManager is
+ * unique to the remoting connection
+ *
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
* @version <tt>$Revision$</tt>
*
@@ -53,10 +56,6 @@
private List msgs;
- //We need to specify the server id too since different servers might have the
- //same consumer id
- private int serverId;
-
private int consumerId;
// Constructors --------------------------------------------------
@@ -65,12 +64,10 @@
{
}
- public ClientDelivery(List msgs, int serverId, int consumerId)
+ public ClientDelivery(List msgs, int consumerId)
{
this.msgs = msgs;
- this.serverId = serverId;
-
this.consumerId = consumerId;
}
@@ -79,8 +76,6 @@
public void write(DataOutputStream out) throws Exception
{
- out.writeInt(serverId);
-
out.writeInt(consumerId);
out.writeInt(msgs.size());
@@ -94,6 +89,8 @@
out.writeByte(mp.getMessage().getType());
out.writeInt(mp.getDeliveryCount());
+
+ out.writeLong(mp.getDeliveryId());
mp.getMessage().write(out);
}
@@ -101,8 +98,6 @@
public void read(DataInputStream in) throws Exception
{
- serverId = in.readInt();
-
consumerId = in.readInt();
int numMessages = in.readInt();
@@ -115,11 +110,13 @@
int deliveryCount = in.readInt();
+ long deliveryId = in.readLong();
+
JBossMessage m = (JBossMessage)MessageFactory.createMessage(type);
m.read(in);
- MessageProxy md = JBossMessage.createThinDelegate(m, deliveryCount);
+ MessageProxy md = JBossMessage.createThinDelegate(deliveryId, m, deliveryCount);
msgs.add(md);
}
@@ -132,11 +129,6 @@
return msgs;
}
- public int getServerId()
- {
- return serverId;
- }
-
public int getConsumerId()
{
return consumerId;
Added: trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,46 @@
+/*
+ * 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.jms.server.endpoint;
+
+/**
+ * A DefaultAck
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class DefaultAck implements Ack
+{
+ private long deliveryId;
+
+ public DefaultAck(long deliveryId)
+ {
+ this.deliveryId = deliveryId;
+ }
+
+ public long getDeliveryId()
+ {
+ return deliveryId;
+ }
+}
Added: trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,98 @@
+/*
+ * 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.jms.server.endpoint;
+
+import org.jboss.jms.message.MessageProxy;
+
+/**
+ * Struct like class for holding information regarding a delivery
+ * on the client side - this is never passed to the server
+ *
+ * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
+ * @author <a href="mailto:ovidiu at jboss.com>Ovidiu Feodorov</a>
+ *
+ * $Id: AckInfo.java 1770 2006-12-12 10:49:42Z timfox $
+ */
+public class DeliveryInfo implements Ack
+{
+ // Constants -----------------------------------------------------
+
+ // Attributes ----------------------------------------------------
+
+ //This is needed on failover when recreating delivery list on the server session
+ //we need to know the channel id so we can recreate the deliveries
+ private long channelID;
+
+ //This is needed when doing local redelivery of messages, since we need to know which
+ //consumer gets the message
+ private int consumerId;
+
+ private MessageProxy msg;
+
+ // Static --------------------------------------------------------
+
+ // Constructors --------------------------------------------------
+
+
+ public DeliveryInfo(MessageProxy msg, int consumerId, long channelID)
+ {
+ this.msg = msg;
+
+ this.consumerId = consumerId;
+
+ this.channelID = channelID;
+ }
+
+ // Public --------------------------------------------------------
+
+ public long getChannelId()
+ {
+ return channelID;
+ }
+
+ public int getConsumerId()
+ {
+ return consumerId;
+ }
+
+ public MessageProxy getMessageProxy()
+ {
+ return msg;
+ }
+
+
+ // Ack Implementation -------------------------------------------
+
+ public long getDeliveryId()
+ {
+ return msg.getDeliveryId();
+ }
+
+ // Protected -----------------------------------------------------
+
+ // Package Private -----------------------------------------------
+
+ // Private -------------------------------------------------------
+
+ // Inner Classes -------------------------------------------------
+
+}
Added: trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,94 @@
+/*
+ * 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.jms.server.endpoint;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
+import org.jboss.messaging.util.Streamable;
+
+/**
+ * A DeliveryRecovery
+ *
+ * Used for sending information about to recover a delivery to the server
+ * on failover
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class DeliveryRecovery implements Streamable
+{
+ private long deliveryId;
+
+ private long messageId;
+
+ private long channelId;
+
+ public DeliveryRecovery()
+ {
+ }
+
+ public DeliveryRecovery(long deliveryId, long messageId, long channelId)
+ {
+ this.deliveryId = deliveryId;
+
+ this.messageId = messageId;
+
+ this.channelId = channelId;
+ }
+
+ public long getDeliveryId()
+ {
+ return deliveryId;
+ }
+
+ public long getMessageId()
+ {
+ return messageId;
+ }
+
+ public long getChannelId()
+ {
+ return channelId;
+ }
+
+ public void read(DataInputStream in) throws Exception
+ {
+ deliveryId = in.readLong();
+
+ messageId = in.readLong();
+
+ channelId = in.readLong();
+ }
+
+ public void write(DataOutputStream out) throws Exception
+ {
+ out.writeLong(deliveryId);
+
+ out.writeLong(messageId);
+
+ out.writeLong(channelId);
+ }
+}
Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -30,6 +30,7 @@
import org.jboss.jms.selector.Selector;
import org.jboss.jms.server.remoting.JMSDispatcher;
+import org.jboss.jms.util.ExceptionUtil;
import org.jboss.logging.Logger;
import org.jboss.messaging.core.Channel;
import org.jboss.messaging.core.Filter;
@@ -65,8 +66,8 @@
// Constructors --------------------------------------------------
- protected ServerBrowserEndpoint(ServerSessionEndpoint session, int id,
- Channel destination, String messageSelector)
+ ServerBrowserEndpoint(ServerSessionEndpoint session, int id,
+ Channel destination, String messageSelector)
throws JMSException
{
this.session = session;
@@ -87,24 +88,38 @@
public boolean hasNextMessage() throws JMSException
{
- if (closed)
+ try
{
- throw new IllegalStateException("Browser is closed");
+ if (closed)
+ {
+ throw new IllegalStateException("Browser is closed");
+ }
+ return iterator.hasNext();
+ }
+ catch (Throwable t)
+ {
+ throw ExceptionUtil.handleJMSInvocation(t, this + " hasNextMessage");
}
- return iterator.hasNext();
}
public Message nextMessage() throws JMSException
{
- if (closed)
+ try
{
- throw new IllegalStateException("Browser is closed");
+ if (closed)
+ {
+ throw new IllegalStateException("Browser is closed");
+ }
+ Routable r = (Routable)iterator.next();
+
+ if (trace) { log.trace("returning the message corresponding to " + r); }
+
+ return (Message)r.getMessage();
+ }
+ catch (Throwable t)
+ {
+ throw ExceptionUtil.handleJMSInvocation(t, this + " nextMessage");
}
- Routable r = (Routable)iterator.next();
-
- if (trace) { log.trace("returning the message corresponding to " + r); }
-
- return (Message)r.getMessage();
}
@@ -112,52 +127,60 @@
//why not just pass back the arraylist??
public Message[] nextMessageBlock(int maxMessages) throws JMSException
{
- if (closed)
+ try
{
- throw new IllegalStateException("Browser is closed");
- }
-
- if (maxMessages < 2)
+ if (closed)
+ {
+ throw new IllegalStateException("Browser is closed");
+ }
+
+ if (maxMessages < 2)
+ {
+ throw new IllegalArgumentException("maxMessages must be >=2 otherwise use nextMessage");
+ }
+
+ ArrayList messages = new ArrayList(maxMessages);
+ int i = 0;
+ while (i < maxMessages)
+ {
+ if (iterator.hasNext())
+ {
+ Message m = (Message)((Routable)iterator.next()).getMessage();
+ messages.add(m);
+ i++;
+ }
+ else break;
+ }
+ return (Message[])messages.toArray(new Message[messages.size()]);
+ }
+ catch (Throwable t)
{
- throw new IllegalArgumentException("maxMessages must be >=2 otherwise use nextMessage");
+ throw ExceptionUtil.handleJMSInvocation(t, this + " nextMessageBlock");
}
-
- ArrayList messages = new ArrayList(maxMessages);
- int i = 0;
- while (i < maxMessages)
- {
- if (iterator.hasNext())
- {
- Message m = (Message)((Routable)iterator.next()).getMessage();
- messages.add(m);
- i++;
- }
- else break;
- }
- return (Message[])messages.toArray(new Message[messages.size()]);
}
-
public void close() throws JMSException
{
- if (closed)
+ try
{
- throw new IllegalStateException("Browser is already closed");
+ localClose();
+
+ session.removeBrowser(id);
+ }
+ catch (Throwable t)
+ {
+ throw ExceptionUtil.handleJMSInvocation(t, this + " close");
}
- iterator = null;
- session.removeBrowserDelegate(id);
- JMSDispatcher.instance.unregisterTarget(new Integer(id));
- closed = true;
}
-
+
public void closing() throws JMSException
{
// Do nothing
}
-
- public boolean isClosed()
+
+ public boolean isClosed() throws JMSException
{
- return closed;
+ throw new IllegalStateException("isClosed should never be handled on the server side");
}
// Public --------------------------------------------------------
@@ -168,8 +191,22 @@
}
// Package protected ---------------------------------------------
+
+ void localClose() throws JMSException
+ {
+ if (closed)
+ {
+ throw new IllegalStateException("Browser is already closed");
+ }
+
+ iterator = null;
+
+ JMSDispatcher.instance.unregisterTarget(new Integer(id));
+
+ closed = true;
+ }
- // Protected -----------------------------------------------------
+ // Protected -----------------------------------------------------
// Private -------------------------------------------------------
Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -21,6 +21,7 @@
*/
package org.jboss.jms.server.endpoint;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -44,9 +45,9 @@
import org.jboss.jms.server.endpoint.advised.SessionAdvised;
import org.jboss.jms.server.remoting.JMSDispatcher;
import org.jboss.jms.server.remoting.JMSWireFormat;
-import org.jboss.jms.tx.AckInfo;
import org.jboss.jms.tx.TransactionRequest;
-import org.jboss.jms.tx.TxState;
+import org.jboss.jms.tx.ClientTransaction;
+import org.jboss.jms.tx.ClientTransaction.SessionTxState;
import org.jboss.jms.util.ExceptionUtil;
import org.jboss.jms.util.ToString;
import org.jboss.logging.Logger;
@@ -55,13 +56,9 @@
import org.jboss.messaging.core.plugin.contract.PostOffice;
import org.jboss.messaging.core.tx.Transaction;
import org.jboss.messaging.core.tx.TransactionRepository;
-import org.jboss.messaging.util.ConcurrentReaderHashSet;
import org.jboss.remoting.Client;
import org.jboss.remoting.callback.ServerInvokerCallbackHandler;
-import org.jboss.util.id.GUID;
-import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
-
/**
* Concrete implementation of ConnectionEndpoint.
*
@@ -83,11 +80,11 @@
private boolean trace = log.isTraceEnabled();
- private boolean closed;
+ private volatile boolean closed;
private volatile boolean started;
- private int connectionID;
+ private int id;
private String remotingClientSessionId;
@@ -124,11 +121,11 @@
private int prefetchSize;
- protected int defaultTempQueueFullSize;
+ private int defaultTempQueueFullSize;
- protected int defaultTempQueuePageSize;
+ private int defaultTempQueuePageSize;
- protected int defaultTempQueueDownCacheSize;
+ private int defaultTempQueueDownCacheSize;
// Constructors --------------------------------------------------
@@ -148,7 +145,7 @@
started = false;
- this.connectionID = serverPeer.getNextObjectID();
+ this.id = serverPeer.getNextObjectID();
this.clientID = clientID;
this.prefetchSize = prefetchSize;
@@ -156,8 +153,8 @@
this.defaultTempQueuePageSize = defaultTempQueuePageSize;
this.defaultTempQueueDownCacheSize = defaultTempQueueDownCacheSize;
- sessions = new ConcurrentReaderHashMap();
- temporaryDestinations = new ConcurrentReaderHashSet();
+ sessions = new HashMap();
+ temporaryDestinations = new HashSet();
this.username = username;
this.password = password;
@@ -184,8 +181,14 @@
// create the corresponding server-side session endpoint and register it with this
// connection endpoint instance
ServerSessionEndpoint ep = new ServerSessionEndpoint(sessionID, this);
- putSessionDelegate(sessionID, ep);
+
+ synchronized (sessions)
+ {
+ sessions.put(new Integer(sessionID), ep);
+ }
+
SessionAdvised sessionAdvised = new SessionAdvised(ep);
+
JMSDispatcher.instance.registerTarget(new Integer(sessionID), sessionAdvised);
ClientSessionDelegate d = new ClientSessionDelegate(sessionID);
@@ -263,8 +266,10 @@
{
throw new IllegalStateException("Connection is closed");
}
+
setStarted(false);
- log.debug("Connection " + connectionID + " stopped");
+
+ log.debug("Connection " + id + " stopped");
}
catch (Throwable t)
{
@@ -284,43 +289,43 @@
return;
}
- // We clone to avoid concurrent modification exceptions
- for(Iterator i = new HashSet(sessions.values()).iterator(); i.hasNext(); )
+ synchronized (sessions)
{
- ServerSessionEndpoint sess = (ServerSessionEndpoint)i.next();
-
- // clear all consumers associated with this session from the serverPeer's cache
- for(Iterator j = sess.getConsumerEndpointIDs().iterator(); j.hasNext(); )
+ for(Iterator i = sessions.values().iterator(); i.hasNext(); )
{
- Integer consumerID = (Integer)j.next();
- serverPeer.removeConsumerEndpoint(consumerID);
+ ServerSessionEndpoint sess = (ServerSessionEndpoint)i.next();
+
+ sess.localClose();
}
-
- // ... and also close the session
- sess.close();
+
+ sessions.clear();
}
- for(Iterator i = temporaryDestinations.iterator(); i.hasNext(); )
+ synchronized (temporaryDestinations)
{
- JBossDestination dest = (JBossDestination)i.next();
-
- if (dest.isQueue())
- {
- postOffice.unbindQueue(dest.getName());
- }
- else
+ for(Iterator i = temporaryDestinations.iterator(); i.hasNext(); )
{
- //No need to unbind - this will already have happened, and all removeAllReferences
- //will have already been called when the subscriptions were closed
- //which always happens before the connection closed (depth first close)
+ JBossDestination dest = (JBossDestination)i.next();
+
+ if (dest.isQueue())
+ {
+ postOffice.unbindQueue(dest.getName());
+ }
+ else
+ {
+ //No need to unbind - this will already have happened, and all removeAllReferences
+ //will have already been called when the subscriptions were closed
+ //which always happens before the connection closed (depth first close)
+ }
}
+
+ temporaryDestinations.clear();
}
-
- temporaryDestinations.clear();
cm.unregisterConnection(jmsClientVMId, remotingClientSessionId);
- JMSDispatcher.instance.unregisterTarget(new Integer(connectionID));
+ JMSDispatcher.instance.unregisterTarget(new Integer(id));
+
closed = true;
}
catch (Throwable t)
@@ -334,11 +339,6 @@
log.trace(this + " closing (noop)");
}
- public boolean isClosed()
- {
- return closed;
- }
-
public void sendTransaction(TransactionRequest request) throws JMSException
{
try
@@ -407,6 +407,11 @@
throw ExceptionUtil.handleJMSInvocation(t, this + " getPreparedTransactions");
}
}
+
+ public boolean isClosed() throws JMSException
+ {
+ throw new IllegalStateException("isClosed should never be handled on the server side");
+ }
// Public --------------------------------------------------------
@@ -468,132 +473,108 @@
this.usingVersion = version;
}
- public byte getUsingVersion()
+
+
+ public String toString()
{
+ return "ConnectionEndpoint[" + id + "]";
+ }
+
+ // Package protected ---------------------------------------------
+
+ byte getUsingVersion()
+ {
return usingVersion;
}
- public int getPrefetchSize()
+ int getPrefetchSize()
{
return prefetchSize;
}
- public int getDefaultTempQueueFullSize()
+ int getDefaultTempQueueFullSize()
{
return defaultTempQueueFullSize;
}
- public int getDefaultTempQueuePageSize()
+ int getDefaultTempQueuePageSize()
{
return defaultTempQueuePageSize;
}
- public int getDefaultTempQueueDownCacheSize()
+ int getDefaultTempQueueDownCacheSize()
{
return defaultTempQueueDownCacheSize;
}
-
- public String toString()
- {
- return "ConnectionEndpoint[" + connectionID + "]";
- }
-
- // Package protected ---------------------------------------------
-
- // Protected -----------------------------------------------------
-
- protected ServerInvokerCallbackHandler getCallbackHandler()
+ ServerInvokerCallbackHandler getCallbackHandler()
{
return callbackHandler;
}
- protected int getConnectionID()
+ int getConnectionID()
{
- return connectionID;
+ return id;
}
- protected boolean isStarted()
+ boolean isStarted()
{
return started;
}
- /**
- * Generates a sessionID that is unique per this ConnectionDelegate instance
- */
- protected String generateSessionID()
+ void removeSession(int sessionId) throws Exception
{
- return new GUID().toString();
+ synchronized (sessions)
+ {
+ if (sessions.remove(new Integer(sessionId)) == null)
+ {
+ throw new IllegalStateException("Cannot find session with id " + sessionId + " to remove");
+ }
+ }
}
-
- protected ServerSessionEndpoint putSessionDelegate(int sessionID, ServerSessionEndpoint d)
- {
- return (ServerSessionEndpoint)sessions.put(new Integer(sessionID), d);
- }
- protected ServerSessionEndpoint getSessionDelegate(int sessionID)
+ void addTemporaryDestination(Destination dest)
{
- return (ServerSessionEndpoint)sessions.get(new Integer(sessionID));
+ synchronized (temporaryDestinations)
+ {
+ temporaryDestinations.add(dest);
+ }
}
- protected ServerSessionEndpoint removeSessionDelegate(int sessionID)
+ void removeTemporaryDestination(Destination dest)
{
- return (ServerSessionEndpoint)sessions.remove(new Integer(sessionID));
+ synchronized (temporaryDestinations)
+ {
+ temporaryDestinations.remove(dest);
+ }
}
- protected ServerConsumerEndpoint putConsumerEndpoint(int consumerID, ServerConsumerEndpoint c)
+ boolean hasTemporaryDestination(Destination dest)
{
- return serverPeer.putConsumerEndpoint(consumerID, c);
+ synchronized (temporaryDestinations)
+ {
+ return temporaryDestinations.contains(dest);
+ }
}
- protected ServerConsumerEndpoint getConsumerEndpoint(int consumerID)
+ ServerPeer getServerPeer()
{
- return serverPeer.getConsumerEndpoint(consumerID);
- }
-
- protected ServerConsumerEndpoint removeConsumerEndpoint(Integer consumerID)
- {
- return serverPeer.removeConsumerEndpoint(consumerID);
- }
-
- protected void addTemporaryDestination(Destination dest)
- {
- temporaryDestinations.add(dest);
- }
-
- protected void removeTemporaryDestination(Destination dest)
- {
- temporaryDestinations.remove(dest);
- }
-
- protected boolean hasTemporaryDestination(Destination dest)
- {
- return temporaryDestinations.contains(dest);
- }
-
- protected ServerPeer getServerPeer()
- {
return serverPeer;
}
- protected String getRemotingClientSessionId()
+ String getRemotingClientSessionId()
{
return remotingClientSessionId;
}
- protected String getJmsClientVMId()
+ void sendMessage(JBossMessage msg, Transaction tx) throws Exception
{
- return jmsClientVMId;
- }
-
- protected void sendMessage(JBossMessage msg, Transaction tx) throws Exception
- {
JBossDestination dest = (JBossDestination)msg.getJMSDestination();
// This allows the no-local consumers to filter out the messages that come from the same
// connection
// TODO Do we want to set this for ALL messages. Optimisation is possible here.
- msg.setConnectionID(connectionID);
+ msg.setConnectionID(id);
// We must reference the message *before* we send it the destination to be handled. This is
// so we can guarantee that the message doesn't disappear from the store before the
@@ -628,7 +609,9 @@
if (trace) { log.trace("sent " + msg); }
}
-
+
+ // Protected -----------------------------------------------------
+
// Private -------------------------------------------------------
private void setStarted(boolean s) throws Throwable
@@ -638,46 +621,41 @@
for (Iterator i = sessions.values().iterator(); i.hasNext(); )
{
ServerSessionEndpoint sd = (ServerSessionEndpoint)i.next();
+
sd.setStarted(s);
}
started = s;
}
}
- private void processTransaction(TxState txState, Transaction tx) throws Throwable
+ private void processTransaction(ClientTransaction txState, Transaction tx) throws Throwable
{
- if (trace) { log.trace("processing transaction, there are " + txState.getMessages().size() + " messages and " + txState.getAcks().size() + " acks "); }
+ if (trace) { log.trace("processing transaction"); }
- for(Iterator i = txState.getMessages().iterator(); i.hasNext(); )
- {
- JBossMessage m = (JBossMessage)i.next();
-
- sendMessage(m, tx);
- }
-
- if (trace) { log.trace("done the sends"); }
-
- // Then ack the acks
-
- List acks = txState.getAcks();
-
- // We create the transactional callbacks in reverse order so if the transaction is
- // subsequently cancelled the refs are put back in the correct order on the queue/subscription
- for (int i = acks.size() - 1; i >= 0; i--)
- {
- AckInfo ack = (AckInfo)acks.get(i);
-
- ServerConsumerEndpoint consumer = getConsumerEndpoint(ack.getConsumerID());
- if (consumer == null)
+ synchronized (sessions)
+ {
+ for (Iterator i = txState.getSessionStates().iterator(); i.hasNext(); )
{
- throw new IllegalStateException("Cannot find consumer " + ack.getConsumerID());
+ SessionTxState sessionState = (SessionTxState)i.next();
+
+ List msgs = sessionState.getMsgs();
+
+ for (Iterator i2 = msgs.iterator(); i2.hasNext(); )
+ {
+ JBossMessage msg = (JBossMessage)i2.next();
+
+ sendMessage(msg, tx);
+ }
+
+ List acks = sessionState.getAcks();
+
+ ServerSessionEndpoint session = (ServerSessionEndpoint)sessions.get(new Integer(sessionState.getSessionId()));
+
+ session.acknowledgeTransactionally(acks, tx);
}
- consumer.acknowledgeTransactionally(ack.getMessageID(), tx);
-
- if (trace) { log.trace("acked " + ack.getMessageID()); }
}
- if (trace) { log.trace("done the acks"); }
+ if (trace) { log.trace("Processed transaction"); }
}
// Inner classes -------------------------------------------------
Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -23,10 +23,7 @@
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import javax.jms.IllegalStateException;
import javax.jms.InvalidSelectorException;
@@ -46,15 +43,12 @@
import org.jboss.messaging.core.Delivery;
import org.jboss.messaging.core.DeliveryObserver;
import org.jboss.messaging.core.MessageReference;
-import org.jboss.messaging.core.Queue;
import org.jboss.messaging.core.Receiver;
import org.jboss.messaging.core.Routable;
import org.jboss.messaging.core.SimpleDelivery;
import org.jboss.messaging.core.plugin.contract.PostOffice;
import org.jboss.messaging.core.plugin.postoffice.Binding;
import org.jboss.messaging.core.tx.Transaction;
-import org.jboss.messaging.core.tx.TransactionException;
-import org.jboss.messaging.core.tx.TxCallback;
import org.jboss.messaging.util.Future;
import org.jboss.remoting.callback.Callback;
@@ -113,28 +107,22 @@
// No need to be volatile - is protected by lock
private boolean closed;
- // No need to be volatile
- private boolean disconnected;
-
private Executor executor;
private int prefetchSize;
private Object lock;
- private Map deliveries;
-
- private Queue dlq;
-
private Object messagesInTransitLock;
+
private int messagesInTransitCount; // access only from a region guarded by messagesInTransitLock
// Constructors --------------------------------------------------
- protected ServerConsumerEndpoint(int id, Channel messageQueue, String queueName,
- ServerSessionEndpoint sessionEndpoint,
- String selector, boolean noLocal, JBossDestination dest,
- int prefetchSize, Queue dlq)
+ ServerConsumerEndpoint(int id, Channel messageQueue, String queueName,
+ ServerSessionEndpoint sessionEndpoint,
+ String selector, boolean noLocal, JBossDestination dest,
+ int prefetchSize)
throws InvalidSelectorException
{
if (trace) { log.trace("constructing consumer endpoint " + id); }
@@ -144,8 +132,7 @@
this.queueName = queueName;
this.sessionEndpoint = sessionEndpoint;
this.prefetchSize = prefetchSize;
- this.dlq = dlq;
-
+
// We always created with clientConsumerFull = true. This prevents the SCD sending messages to
// the client before the client has fully finished creating the MessageCallbackHandler.
this.clientConsumerFull = true;
@@ -170,6 +157,7 @@
// using the same queuedexecutor concurrently if there are a lot of active consumers.
this.noLocal = noLocal;
+
this.destination = dest;
this.toDeliver = new ArrayList();
@@ -182,24 +170,14 @@
this.messageSelector = new Selector(selector);
if (trace) log.trace("created selector");
}
-
- //TODO -
- //We really need to get rid of this delivery list - it's only purpose in life is to solve
- //the race condition where acks or cancels can come in before handle has returned - and
- //that can be solved in a simpler way anyway.
- //It adds extra complexity both in all the extra code necessary to maintain it, the extra memory
- //needed to maintain it, the extra complexity in synchronization on this class to protect access to it
- //and when we do clustering we will have to replicate it too!!
- //Let's GET RID OF IT!!!!!!!!!!!
- this.deliveries = new LinkedHashMap();
-
+
this.started = this.sessionEndpoint.getConnectionEndpoint().isStarted();
// adding the consumer to the queue
this.messageQueue.add(this);
// prompt delivery
- messageQueue.deliver(false);
+ promptDelivery();
messagesInTransitLock = new Object();
messagesInTransitCount = 0;
@@ -234,12 +212,6 @@
// queue for delivery later.
if (!started)
{
- // this is a common programming error, make this visible in the debug logs. However,
- // make also possible to cut out the performance overhead for systems that raise the
- // threshold to INFO or higher.
-
- //TODO - Why was this debug
- //log.isDebugEnabled is too slow!! especially on the primary execution path
if (trace) { log.trace(this + " NOT started yet!"); }
return null;
@@ -262,15 +234,15 @@
{
return delivery;
}
+
+ long deliveryId = sessionEndpoint.addDelivery(delivery);
- deliveries.put(new Long(ref.getMessageID()), delivery);
-
// We don't send the message as-is, instead we create a MessageProxy instance. This allows
// local fields such as deliveryCount to be handled by the proxy but global data to be
// fielded by the same underlying Message instance. This allows us to avoid expensive
// copying of messages
- MessageProxy mp = JBossMessage.createThinDelegate(message, ref.getDeliveryCount());
+ MessageProxy mp = JBossMessage.createThinDelegate(deliveryId, message, ref.getDeliveryCount());
// Add the proxy to the list to deliver
@@ -319,9 +291,7 @@
{
int conId = ((JBossMessage)r).getConnectionID();
- if (trace) { log.trace("message connection id: " + conId); }
-
- if (trace) { log.trace("current connection connection id: " + sessionEndpoint.getConnectionEndpoint().getConnectionID()); }
+ if (trace) { log.trace("message connection id: " + conId + " current connection connection id: " + sessionEndpoint.getConnectionEndpoint().getConnectionID()); }
accept = conId != sessionEndpoint.getConnectionEndpoint().getConnectionID();
@@ -352,56 +322,16 @@
{
try
{
- synchronized (lock)
- {
- // On close we only disconnect the consumer from the queue we don't actually remove
- // it. This is because it may still contain deliveries that may well be acknowledged
- // after the consumer has closed. This is perfectly valid.
-
- // TODO - The deliveries should really be stored in the session endpoint, not here
- // that is their natural place, that would mean we wouldn't have to mess around with
- // keeping deliveries after this is closed.
-
- if (trace) { log.trace(this + " grabbed the main lock in close()"); }
-
- disconnect();
-
- JMSDispatcher.instance.unregisterTarget(new Integer(id));
-
- // If this is a consumer of a non durable subscription then we want to unbind the
- // subscription and delete all its data.
-
- if (destination.isTopic())
- {
- PostOffice postOffice =
- sessionEndpoint.getConnectionEndpoint().getServerPeer().getPostOfficeInstance();
-
- Binding binding = postOffice.getBindingForQueueName(queueName);
-
- //Note binding can be null since there can many competing subscribers for the subscription -
- //in which case the first will have removed the subscription and subsequently
- //ones won't find it
-
- if (binding != null && !binding.getQueue().isRecoverable())
- {
- postOffice.unbindQueue(queueName);
- }
- }
-
- closed = true;
- }
- }
+ localClose();
+
+ sessionEndpoint.removeConsumer(id);
+ }
catch (Throwable t)
{
throw ExceptionUtil.handleJMSInvocation(t, this + " close");
}
}
-
- public boolean isClosed()
- {
- return closed;
- }
-
+
// ConsumerEndpoint implementation -------------------------------
/*
@@ -475,6 +405,11 @@
messagesInTransitLock.notifyAll();
}
}
+
+ public boolean isClosed() throws JMSException
+ {
+ throw new IllegalStateException("isClosed should never be handled on the server side");
+ }
// Public --------------------------------------------------------
@@ -493,188 +428,43 @@
return sessionEndpoint;
}
- public int getId()
- {
- return id;
- }
-
// Package protected ---------------------------------------------
- // Protected -----------------------------------------------------
-
- protected void acknowledgeTransactionally(long messageID, Transaction tx) throws Throwable
- {
- if (trace) { log.trace("acknowledging transactionally " + messageID); }
-
- Delivery d = null;
-
- // The actual removal of the deliveries from the delivery list is deferred until tx commit
+ void localClose() throws Throwable
+ {
synchronized (lock)
- {
- d = (Delivery)deliveries.get(new Long(messageID));
- }
-
- DeliveryCallback deliveryCallback = (DeliveryCallback)tx.getCallback(this);
-
- if (deliveryCallback == null)
- {
- deliveryCallback = new DeliveryCallback();
- tx.addCallback(deliveryCallback, this);
- }
- deliveryCallback.addMessageID(messageID);
+ {
+ if (trace) { log.trace(this + " grabbed the main lock in close() " + this); }
+
+ messageQueue.remove(this);
- if (d != null)
- {
- d.acknowledge(tx);
- }
- else
- {
- //throw new IllegalStateException("Could not find delivery to acknowledge");
- //TODO - Reenable this exception
- log.warn("Coud not find acknowledge... Exception disabled for tests.. please re-enable before merging into trunk");
- }
- }
-
- protected void acknowledge(long messageID) throws Throwable
- {
- // acknowledge a delivery
- Delivery d;
-
- synchronized (lock)
- {
- d = (Delivery)deliveries.remove(new Long(messageID));
- }
-
- if (d != null)
- {
- d.acknowledge(null);
- }
- else
- {
- throw new IllegalStateException("Cannot find delivery to acknowledge:" + messageID);
- }
- }
-
- /**
- * Actually remove the consumer and clear up any deliveries it may have
- * This is called by the session on session.close()
- * We can get rid of this when we store the deliveries on the session
- *
- **/
- protected void remove() throws Throwable
- {
- if (trace) log.trace("attempting to remove receiver " + this + " from destination " + messageQueue);
-
- boolean wereDeliveries = false;
- for(Iterator i = deliveries.values().iterator(); i.hasNext(); )
- {
+ JMSDispatcher.instance.unregisterTarget(new Integer(id));
+
+ // If this is a consumer of a non durable subscription then we want to unbind the
+ // subscription and delete all its data.
- Delivery d = (Delivery)i.next();
-
- d.cancel();
- wereDeliveries = true;
- }
- deliveries.clear();
-
- if (!disconnected)
- {
- if (!closed)
+ if (destination.isTopic())
{
- close();
- }
- }
-
- sessionEndpoint.getConnectionEndpoint().
- getServerPeer().removeConsumerEndpoint(new Integer(id));
+ PostOffice postOffice =
+ sessionEndpoint.getConnectionEndpoint().getServerPeer().getPostOfficeInstance();
- sessionEndpoint.removeConsumerEndpoint(id);
-
- if (wereDeliveries)
- {
- //If we cancelled any deliveries we need to force a deliver on the queue
- //This is because there may be other waiting competing consumers who need a chance to get
- //any of the cancelled messages
- messageQueue.deliver(false);
- }
- }
-
- protected void promptDelivery()
- {
- messageQueue.deliver(false);
- }
-
- protected void sendToDLQ(Long messageID, Transaction tx) throws Throwable
- {
- Delivery del = (Delivery)deliveries.remove(messageID);
-
- if (del != null)
- {
- log.warn(del.getReference() + " has exceed maximum delivery attempts and will be sent to the DLQ");
-
- if (dlq != null)
- {
- //reset delivery count to zero
- del.getReference().setDeliveryCount(0);
-
- dlq.handle(null, del.getReference(), tx);
-
- del.acknowledge(tx);
- }
- else
- {
- log.warn("Cannot send to DLQ since DLQ has not been deployed! The message will be removed");
-
- del.acknowledge(tx);
- }
- }
- else
- {
- throw new IllegalStateException("Cannot find delivery to send to DLQ:" + id);
- }
-
- }
+ Binding binding = postOffice.getBindingForQueueName(queueName);
- protected void createDeliveries(List messageIds) throws Throwable
- {
- List dels = messageQueue.createDeliveries(messageIds);
+ //Note binding can be null since there can many competing subscribers for the subscription -
+ //in which case the first will have removed the subscription and subsequently
+ //ones won't find it
- synchronized (lock)
- {
- Iterator iter = dels.iterator();
-
- while (iter.hasNext())
- {
- Delivery del = (Delivery)iter.next();
-
- deliveries.put(new Long(del.getReference().getMessageID()), del);
+ if (binding != null && !binding.getQueue().isRecoverable())
+ {
+ postOffice.unbindQueue(queueName);
+ }
}
+
+ closed = true;
}
-
- //Prompt delivery
- messageQueue.deliver(false);
- }
-
- protected void cancelDelivery(Long messageID, int deliveryCount) throws Throwable
- {
- Delivery del = (Delivery)deliveries.remove(messageID);
-
- if (del != null)
- {
- //Cancel back to the queue
-
- //Update the delivery count
+ }
- del.getReference().setDeliveryCount(deliveryCount);
-
- del.cancel();
- }
- else
- {
- throw new IllegalStateException("Cannot find delivery to cancel:" + id);
- }
- }
-
- protected void start()
+ void start()
{
synchronized (lock)
{
@@ -693,10 +483,10 @@
}
// Prompt delivery
- messageQueue.deliver(false);
+ promptDelivery();
}
- protected void stop() throws Throwable
+ void stop() throws Throwable
{
// We need to:
// - Stop accepting any new messages in the SCE.
@@ -707,8 +497,7 @@
// already executing and messages might get deposited after.
synchronized (lock)
{
- // can't start or stop it if it is closed
- if (closed)
+ if (!started)
{
return;
}
@@ -762,36 +551,35 @@
{
synchronized (lock)
{
+ //Cancel in reverse order
for (int i = toDeliver.size() - 1; i >= 0; i--)
{
MessageProxy proxy = (MessageProxy)toDeliver.get(i);
- long id = proxy.getMessage().getMessageID();
- cancelDelivery(new Long(id), proxy.getMessage().getDeliveryCount());
+
+ sessionEndpoint.cancelDelivery(proxy.getDeliveryId());
}
}
toDeliver.clear();
+
bufferFull = false;
}
+
+ //Need to prompt delivery
+ promptDelivery();
}
+
+
+
+ // Protected -----------------------------------------------------
// Private -------------------------------------------------------
- /**
- * Disconnect this consumer from the queue that feeds it. This method does not clear up
- * deliveries
- */
- private void disconnect()
+ private void promptDelivery()
{
- boolean removed = messageQueue.remove(this);
-
- if (removed)
- {
- disconnected = true;
- if (trace) { log.trace(this + " removed from the queue"); }
- }
+ messageQueue.deliver(false);
}
-
+
// Inner classes -------------------------------------------------
/*
@@ -835,12 +623,7 @@
ServerConnectionEndpoint connection =
ServerConsumerEndpoint.this.sessionEndpoint.getConnectionEndpoint();
- int serverId = connection.getServerPeer().getServerPeerID();
-
- // TODO How can we ensure that messages for the same consumer aren't delivered
- // concurrently to the same consumer on different threads?
-
- ClientDelivery del = new ClientDelivery(list, serverId, id);
+ ClientDelivery del = new ClientDelivery(list, id);
MessagingMarshallable mm = new MessagingMarshallable(connection.getUsingVersion(), del);
Callback callback = new Callback(mm);
@@ -902,63 +685,5 @@
{
result.setResult(null);
}
- }
-
- /**
- *
- * The purpose of this class is to remove deliveries from the delivery list on commit
- * Each transaction has once instance of this per SCE
- *
- */
- private class DeliveryCallback implements TxCallback
- {
- List delList = new ArrayList();
-
- public void beforePrepare()
- {
- //NOOP
- }
-
- public void beforeCommit(boolean onePhase)
- {
- //NOOP
- }
-
- public void beforeRollback(boolean onePhase)
- {
- //NOOP
- }
-
- public void afterPrepare()
- {
- //NOOP
- }
-
- public synchronized void afterCommit(boolean onePhase) throws TransactionException
- {
- // Remove the deliveries from the delivery map.
- Iterator iter = delList.iterator();
- while (iter.hasNext())
- {
- Long messageID = (Long)iter.next();
-
- if (deliveries.remove(messageID) == null)
- {
- //throw new TransactionException("Failed to remove delivery " + messageID);
- log.warn("Couldn't remove delivery " + messageID + "- reenable exception before merging into trunk");
- //TODO reenable exception
- }
- }
- }
-
- public void afterRollback(boolean onePhase) throws TransactionException
- {
- //NOOP
- }
-
- synchronized void addMessageID(long messageID)
- {
- delList.add(new Long(messageID));
- }
- }
+ }
}
Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -24,11 +24,11 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -56,11 +56,12 @@
import org.jboss.jms.server.endpoint.advised.BrowserAdvised;
import org.jboss.jms.server.endpoint.advised.ConsumerAdvised;
import org.jboss.jms.server.remoting.JMSDispatcher;
-import org.jboss.jms.tx.AckInfo;
import org.jboss.jms.util.ExceptionUtil;
import org.jboss.jms.util.MessageQueueNameHelper;
import org.jboss.logging.Logger;
+import org.jboss.messaging.core.Channel;
import org.jboss.messaging.core.Delivery;
+import org.jboss.messaging.core.DeliveryObserver;
import org.jboss.messaging.core.Queue;
import org.jboss.messaging.core.local.PagingFilteredQueue;
import org.jboss.messaging.core.plugin.IdManager;
@@ -72,10 +73,14 @@
import org.jboss.messaging.core.plugin.postoffice.cluster.LocalClusteredQueue;
import org.jboss.messaging.core.plugin.postoffice.cluster.RemoteQueueStub;
import org.jboss.messaging.core.tx.Transaction;
+import org.jboss.messaging.core.tx.TransactionException;
import org.jboss.messaging.core.tx.TransactionRepository;
+import org.jboss.messaging.core.tx.TxCallback;
import org.jboss.util.id.GUID;
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
/**
* Concrete implementation of SessionEndpoint.
@@ -99,9 +104,9 @@
private boolean trace = log.isTraceEnabled();
- private int sessionID;
+ private int id;
- private boolean closed;
+ private volatile boolean closed;
private ServerConnectionEndpoint connectionEndpoint;
@@ -120,12 +125,18 @@
private int maxDeliveryAttempts;
private Queue dlq;
+ // Map < deliveryId, Delivery>
+ private Map deliveries;
+
+ private SynchronizedLong deliveryIdSequence;
+
+
// Constructors --------------------------------------------------
- protected ServerSessionEndpoint(int sessionID, ServerConnectionEndpoint connectionEndpoint)
+ ServerSessionEndpoint(int sessionID, ServerConnectionEndpoint connectionEndpoint)
throws Exception
{
- this.sessionID = sessionID;
+ this.id = sessionID;
this.connectionEndpoint = connectionEndpoint;
@@ -146,7 +157,10 @@
dlq = sp.getDLQ();
tr = sp.getTxRepository();
maxDeliveryAttempts = sp.getMaxDeliveryAttempts();
-
+
+ deliveries = new ConcurrentHashMap();
+
+ deliveryIdSequence = new SynchronizedLong(0);
}
// SessionDelegate implementation --------------------------------
@@ -213,7 +227,11 @@
ServerBrowserEndpoint ep =
new ServerBrowserEndpoint(this, browserID, (PagingFilteredQueue)binding.getQueue(), messageSelector);
- putBrowserDelegate(browserID, ep);
+ //Still need to synchronized since close() can come in on a different thread
+ synchronized (browsers)
+ {
+ browsers.put(new Integer(browserID), ep);
+ }
JMSDispatcher.instance.registerTarget(new Integer(browserID), new BrowserAdvised(ep));
@@ -276,49 +294,27 @@
throw ExceptionUtil.handleJMSInvocation(t, this + " createTopic");
}
}
-
+
public void close() throws JMSException
{
try
{
- if (closed)
- {
- throw new IllegalStateException("Session is already closed");
- }
+ localClose();
- if (trace) log.trace(this + " close()");
-
- // clone to avoid ConcurrentModificationException
- HashSet consumerSet = new HashSet(consumers.values());
-
- for(Iterator i = consumerSet.iterator(); i.hasNext(); )
- {
- ((ServerConsumerEndpoint)i.next()).remove();
- }
-
- connectionEndpoint.removeSessionDelegate(sessionID);
-
- JMSDispatcher.instance.unregisterTarget(new Integer(sessionID));
-
- closed = true;
+ connectionEndpoint.removeSession(id);
}
catch (Throwable t)
{
throw ExceptionUtil.handleJMSInvocation(t, this + " close");
}
}
-
+
public void closing() throws JMSException
{
// currently does nothing
if (trace) log.trace(this + " closing (noop)");
}
-
- public boolean isClosed()
- {
- return closed;
- }
-
+
public void send(JBossMessage message) throws JMSException
{
try
@@ -331,17 +327,24 @@
}
}
- public void acknowledgeBatch(List ackInfos) throws JMSException
+ public void acknowledgeBatch(List acks) throws JMSException
{
try
{
- Iterator iter = ackInfos.iterator();
+ Iterator iter = acks.iterator();
while (iter.hasNext())
{
- AckInfo ackInfo = (AckInfo)iter.next();
+ Ack ack = (Ack)iter.next();
- acknowledgeInternal(ackInfo);
+ Delivery del = (Delivery)deliveries.remove(new Long(ack.getDeliveryId()));
+
+ if (del == null)
+ {
+ throw new IllegalStateException("Cannot find delivery to acknowledge: " + ack.getDeliveryId());
+ }
+
+ del.acknowledge(null);
}
}
catch (Throwable t)
@@ -350,56 +353,63 @@
}
}
- public void acknowledge(AckInfo ackInfo) throws JMSException
+ public void acknowledge(Ack ack) throws JMSException
{
try
{
- acknowledgeInternal(ackInfo);
+ Delivery del = (Delivery)deliveries.remove(new Long(ack.getDeliveryId()));
+
+ if (del == null)
+ {
+ throw new IllegalStateException("Cannot find delivery to acknowledge: " + ack.getDeliveryId());
+ }
+
+ del.acknowledge(null);
}
catch (Throwable t)
{
throw ExceptionUtil.handleJMSInvocation(t, this + " acknowledge");
}
- }
+ }
- public void cancelDeliveries(List ackInfos) throws JMSException
+ public void cancelDeliveries(List cancels) throws JMSException
{
try
{
// deliveries must be cancelled in reverse order
-
- Set consumers = new HashSet();
-
+
List forDLQ = null;
- for (int i = ackInfos.size() - 1; i >= 0; i--)
+ Set channels = new HashSet();
+
+ for (int i = cancels.size() - 1; i >= 0; i--)
{
- AckInfo ack = (AckInfo)ackInfos.get(i);
+ Cancel cancel = (Cancel)cancels.get(i);
- // We look in the global map since the message might have come from connection consumer
- ServerConsumerEndpoint consumer =
- this.connectionEndpoint.getConsumerEndpoint(ack.getConsumerID());
-
- if (consumer == null)
+ Delivery del = (Delivery)deliveries.remove(new Long(cancel.getDeliveryId()));
+
+ if (del == null)
{
- throw new IllegalArgumentException("Cannot find consumer id: " + ack.getConsumerID());
+ throw new IllegalStateException("Cannot find delivery to cancel " + cancel.getDeliveryId());
}
-
- if (ack.getDeliveryCount() >= maxDeliveryAttempts)
+
+ if (cancel.getDeliveryCount() >= maxDeliveryAttempts)
{
if (forDLQ == null)
{
forDLQ = new ArrayList();
}
- forDLQ.add(ack);
+ forDLQ.add(del);
}
else
- {
- consumer.cancelDelivery(new Long(ack.getMessageID()), ack.getDeliveryCount());
+ {
+ del.getReference().setDeliveryCount(cancel.getDeliveryCount());
+
+ del.cancel();
+
+ channels.add(del.getObserver());
}
-
- consumers.add(consumer);
}
//Send stuff to DLQ
@@ -414,17 +424,23 @@
{
for (int i = forDLQ.size() - 1; i >= 0; i--)
{
- AckInfo ack = (AckInfo)forDLQ.get(i);
+ Delivery del = (Delivery)forDLQ.get(i);
- ServerConsumerEndpoint consumer =
- this.connectionEndpoint.getConsumerEndpoint(ack.getConsumerID());
-
- if (consumer == null)
+ if (dlq != null)
+ {
+ //reset delivery count to zero
+ del.getReference().setDeliveryCount(0);
+
+ dlq.handle(null, del.getReference(), tx);
+
+ del.acknowledge(tx);
+ }
+ else
{
- throw new IllegalArgumentException("Cannot find consumer id: " + ack.getConsumerID());
- }
-
- consumer.sendToDLQ(new Long(ack.getMessageID()), tx);
+ log.warn("Cannot send to DLQ since DLQ has not been deployed! The message will be removed");
+
+ del.acknowledge(tx);
+ }
}
tx.commit();
@@ -437,49 +453,49 @@
}
}
- // need to prompt delivery for all consumers
+ // need to prompt delivery for all affected channels
- for(Iterator i = consumers.iterator(); i.hasNext(); )
- {
- ServerConsumerEndpoint consumer = (ServerConsumerEndpoint)i.next();
- consumer.promptDelivery();
- }
+ promptDelivery(channels);
}
catch (Throwable t)
{
throw ExceptionUtil.handleJMSInvocation(t, this + " cancelDeliveries");
}
- }
+ }
- public void sendUnackedAckInfos(List ackInfos) throws JMSException
+ public void recoverDeliveries(List deliveryRecoveryInfos) throws JMSException
{
+ if (trace) { log.trace(this + "recoverDeliveries(): " + deliveryRecoveryInfos); }
try
{
- //Sort into different list for each consumer
+ if (postOffice.isLocal())
+ {
+ throw new IllegalStateException("Recovering deliveries but post office is not clustered!");
+ }
+
+ ClusteredPostOffice po = (ClusteredPostOffice)postOffice;
+
+ long maxDeliveryId = 0;
+
+ //Sort into different list for each channel
Map ackMap = new HashMap();
- for (int i = ackInfos.size() - 1; i >= 0; i--)
+ for (Iterator iter = deliveryRecoveryInfos.iterator(); iter.hasNext(); )
{
- AckInfo ack = (AckInfo)ackInfos.get(i);
+ DeliveryRecovery deliveryInfo = (DeliveryRecovery)iter.next();
+
+ Long channelId = new Long(deliveryInfo.getChannelId());
- ServerConsumerEndpoint consumer =
- this.connectionEndpoint.getConsumerEndpoint(ack.getConsumerID());
-
- if (consumer == null)
- {
- throw new IllegalArgumentException("Cannot find consumer id: " + ack.getConsumerID());
- }
+ List acks = (List)ackMap.get(channelId);
- LinkedList acks = (LinkedList)ackMap.get(consumer);
-
if (acks == null)
{
- acks = new LinkedList();
+ acks = new ArrayList();
- ackMap.put(consumer, acks);
+ ackMap.put(channelId, acks);
}
- acks.addFirst(new Long(ack.getMessageID()));
+ acks.add(deliveryInfo);
}
Iterator iter = ackMap.entrySet().iterator();
@@ -488,19 +504,59 @@
{
Map.Entry entry = (Map.Entry)iter.next();
- ServerConsumerEndpoint consumer = (ServerConsumerEndpoint)entry.getKey();
+ Long channelId = (Long)entry.getKey();
+ //Look up channel
+ Binding binding = po.getBindingforChannelId(channelId.longValue());
+
+ if (binding == null)
+ {
+ throw new IllegalStateException("Cannot find channel with id: " + channelId);
+ }
+
List acks = (List)entry.getValue();
- consumer.createDeliveries(acks);
+ List ids = new ArrayList(acks.size());
+
+ for (Iterator iter2 = acks.iterator(); iter2.hasNext(); )
+ {
+ DeliveryRecovery info = (DeliveryRecovery)iter2.next();
+
+ ids.add(new Long(info.getMessageId()));
+ }
+
+ Queue queue = binding.getQueue();
+
+ List dels = queue.createDeliveries(ids);
+
+ Iterator iter2 = dels.iterator();
+
+ Iterator iter3 = acks.iterator();
+
+ while (iter2.hasNext())
+ {
+ Delivery del = (Delivery)iter2.next();
+
+ DeliveryRecovery info = (DeliveryRecovery)iter3.next();
+
+ long deliveryId = info.getDeliveryId();
+
+ maxDeliveryId = Math.max(maxDeliveryId, deliveryId);
+
+ if (trace) { log.trace(this + " Recovered delivery " + deliveryId + ", " + del); }
+
+ deliveries.put(new Long(deliveryId), del);
+ }
}
+
+ this.deliveryIdSequence = new SynchronizedLong(maxDeliveryId + 1);
}
catch (Throwable t)
{
- throw ExceptionUtil.handleJMSInvocation(t, this + " sendUnackedAckInfos");
+ throw ExceptionUtil.handleJMSInvocation(t, this + " recoverDeliveries");
}
}
-
+
public void addTemporaryDestination(JBossDestination dest) throws JMSException
{
try
@@ -670,6 +726,11 @@
throw ExceptionUtil.handleJMSInvocation(t, this + " unsubscribe");
}
}
+
+ public boolean isClosed() throws JMSException
+ {
+ throw new IllegalStateException("isClosed should never be handled on the server side");
+ }
// Public --------------------------------------------------------
@@ -680,57 +741,184 @@
public String toString()
{
- return "SessionEndpoint[" + sessionID + "]";
+ return "SessionEndpoint[" + id + "]";
}
// Package protected ---------------------------------------------
-
- /**
- * @return a Set<Integer>
- */
- Set getConsumerEndpointIDs()
+
+ void removeBrowser(int browserId) throws Exception
{
- return consumers.keySet();
+ synchronized (browsers)
+ {
+ if (browsers.remove(new Integer(browserId)) == null)
+ {
+ throw new IllegalStateException("Cannot find browser with id " + browserId + " to remove");
+ }
+ }
}
- // Protected -----------------------------------------------------
-
- protected ServerConsumerEndpoint putConsumerEndpoint(int consumerID, ServerConsumerEndpoint d)
+ void removeConsumer(int consumerId) throws Exception
{
- if (trace) { log.trace(this + " caching consumer " + consumerID); }
- return (ServerConsumerEndpoint)consumers.put(new Integer(consumerID), d);
+ synchronized (consumers)
+ {
+ if (consumers.remove(new Integer(consumerId)) == null)
+ {
+ throw new IllegalStateException("Cannot find consumer with id " + consumerId + " to remove");
+ }
+ }
}
+
+// void promptDeliveryOnConsumers()
+// {
+// if (trace) { log.trace(this + " promptDeliveryOnConsumers(), there are " + consumers.size() + " consumers"); }
+// synchronized (consumers)
+// {
+// for (Iterator i = consumers.values().iterator(); i.hasNext(); )
+// {
+// ServerConsumerEndpoint consumer = (ServerConsumerEndpoint)i.next();
+//
+// consumer.promptDelivery();
+// }
+// }
+// }
+
+ void localClose() throws Throwable
+ {
+ if (closed)
+ {
+ throw new IllegalStateException("Session is already closed");
+ }
+
+ if (trace) log.trace(this + " close()");
+
+ synchronized (consumers)
+ {
+ for( Iterator i = consumers.values().iterator(); i.hasNext(); )
+ {
+ ((ServerConsumerEndpoint)i.next()).localClose();
+ }
+
+ consumers.clear();
+ }
+
+ synchronized (browsers)
+ {
+ for( Iterator i = browsers.values().iterator(); i.hasNext(); )
+ {
+ ((ServerBrowserEndpoint)i.next()).localClose();
+ }
+
+ browsers.clear();
+ }
+
+ //Now cancel any remaining deliveries in reverse delivery order
+ //Note we don't maintain order using a LinkedHashMap since then we lose
+ //concurrency since we would have to lock it exclusively
+
+ List entries = new ArrayList(deliveries.entrySet());
+
+ //Sort them in reverse delivery id order
+ Collections.sort(entries,
+ new Comparator()
+ {
+ public int compare(Object obj1, Object obj2)
+ {
+ Map.Entry entry1 = (Map.Entry)obj1;
+ Map.Entry entry2 = (Map.Entry)obj2;
+ Long id1 = (Long)entry1.getKey();
+ Long id2 = (Long)entry2.getKey();
+ return id2.compareTo(id1);
+ }
+ });
- protected ServerConsumerEndpoint getConsumerEndpoint(int consumerID)
- {
- return (ServerConsumerEndpoint)consumers.get(new Integer(consumerID));
- }
+ Iterator iter = entries.iterator();
+
+ Set channels = new HashSet();
+
+ if (trace) { log.trace("Cancelling " + entries.size() + " deliveries"); }
+
+ while (iter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry)iter.next();
+
+ if (trace) { log.trace("Cancelling delivery with delivery id: " + entry.getKey()); }
+
+ Delivery del = (Delivery)entry.getValue();
+
+ del.cancel();
+
+ channels.add(del.getObserver());
+ }
+
+ promptDelivery(channels);
+
+ deliveries.clear();
+
+ JMSDispatcher.instance.unregisterTarget(new Integer(id));
+
+ closed = true;
+ }
- protected ServerConsumerEndpoint removeConsumerEndpoint(int consumerID)
+ void cancelDelivery(long deliveryId) throws Throwable
{
- if (trace) { log.trace(this + " removing consumer " + consumerID + " from cache"); }
- return (ServerConsumerEndpoint)consumers.remove(new Integer(consumerID));
+ Delivery del = (Delivery)deliveries.remove(new Long(deliveryId));
+
+ if (del == null)
+ {
+ throw new IllegalStateException("Cannot find delivery to cancel " + deliveryId);
+ }
+
+ del.cancel();
}
- protected ServerBrowserEndpoint putBrowserDelegate(int browserID, ServerBrowserEndpoint sbd)
+ long addDelivery(Delivery del)
{
- return (ServerBrowserEndpoint)browsers.put(new Integer(browserID), sbd);
+ long deliveryId = deliveryIdSequence.increment();
+
+ deliveries.put(new Long(deliveryId), del);
+
+ if (trace) { log.trace(this + " Added delivery: " + deliveryId + ", " + del); }
+
+ return deliveryId;
}
- protected ServerBrowserEndpoint getBrowserDelegate(int browserID)
+ void acknowledgeTransactionally(List acks, Transaction tx) throws Throwable
{
- return (ServerBrowserEndpoint)browsers.get(new Integer(browserID));
+ if (trace) { log.trace("Acknowledging transactionally " + acks.size() + " for tx: " + tx); }
+
+ DeliveryCallback deliveryCallback = (DeliveryCallback)tx.getCallback(this);
+
+ if (deliveryCallback == null)
+ {
+ deliveryCallback = new DeliveryCallback();
+ tx.addCallback(deliveryCallback, this);
+ }
+
+ Iterator iter = acks.iterator();
+
+ while (iter.hasNext())
+ {
+ Ack ack = (Ack)iter.next();
+
+ Long id = new Long(ack.getDeliveryId());
+
+ Delivery del = (Delivery)deliveries.get(id);
+
+ if (del == null)
+ {
+ throw new IllegalStateException("Cannot find delivery to acknowledge " + ack);
+ }
+
+ deliveryCallback.addDeliveryId(id);
+
+ del.acknowledge(tx);
+ }
}
- protected ServerBrowserEndpoint removeBrowserDelegate(int browserID)
- {
- return (ServerBrowserEndpoint)browsers.remove(new Integer(browserID));
- }
-
/**
* Starts this session's Consumers
*/
- protected void setStarted(boolean s) throws Throwable
+ void setStarted(boolean s) throws Throwable
{
synchronized(consumers)
{
@@ -747,26 +935,12 @@
}
}
}
- }
+ }
+ // Protected -----------------------------------------------------
+
// Private -------------------------------------------------------
-
- private void acknowledgeInternal(AckInfo ackInfo) throws Throwable
- {
- //If the message was delivered via a connection consumer then the message needs to be acked
- //via the original consumer that was used to feed the connection consumer - which
- //won't be one of the consumers of this session
- //Therefore we always look in the global map of consumers held in the server peer
- ServerConsumerEndpoint consumer = this.connectionEndpoint.getConsumerEndpoint(ackInfo.getConsumerID());
-
- if (consumer == null)
- {
- throw new IllegalArgumentException("Cannot find consumer id: " + ackInfo.getConsumerID());
- }
- consumer.acknowledge(ackInfo.getMessageID());
- }
-
private ConsumerDelegate failoverConsumer(JBossDestination jmsDestination,
String selectorString,
boolean noLocal, String subscriptionName,
@@ -804,27 +978,27 @@
new ServerConsumerEndpoint(consumerID, binding.getQueue(),
binding.getQueue().getName(), this, selectorString, noLocal,
- jmsDestination, prefetchSize, dlq);
+ jmsDestination, prefetchSize);
JMSDispatcher.instance.registerTarget(new Integer(consumerID), new ConsumerAdvised(ep));
ClientConsumerDelegate stub =
new ClientConsumerDelegate(consumerID, binding.getQueue().getChannelID(),
prefetchSize, maxDeliveryAttempts);
+
+ synchronized (consumers)
+ {
+ consumers.put(new Integer(consumerID), ep);
+ }
-
- putConsumerEndpoint(consumerID, ep); // caching consumer locally
-
- connectionEndpoint.getServerPeer().putConsumerEndpoint(consumerID, ep); // cachin consumer in server peer
-
return stub;
}
private ConsumerDelegate createConsumerDelegateInternal(JBossDestination jmsDestination,
- String selectorString,
- boolean noLocal,
- String subscriptionName,
- boolean isCC) throws Throwable
+ String selectorString,
+ boolean noLocal,
+ String subscriptionName,
+ boolean isCC) throws Throwable
{
if (closed)
{
@@ -993,8 +1167,10 @@
if (trace) { log.trace("selector " + (selectorChanged ? "has" : "has NOT") + " changed"); }
- boolean topicChanged = !binding.getCondition().equals(jmsDestination.getName());
+ JMSCondition cond = (JMSCondition)binding.getCondition();
+ boolean topicChanged = !cond.getName().equals(jmsDestination.getName());
+
if (log.isTraceEnabled()) { log.trace("topic " + (topicChanged ? "has" : "has NOT") + " changed"); }
if (selectorChanged || topicChanged)
@@ -1069,7 +1245,7 @@
ServerConsumerEndpoint ep =
new ServerConsumerEndpoint(consumerID, (PagingFilteredQueue)binding.getQueue(),
binding.getQueue().getName(), this, selectorString, noLocal,
- jmsDestination, prefetchSize, dlq);
+ jmsDestination, prefetchSize);
JMSDispatcher.instance.registerTarget(new Integer(consumerID), new ConsumerAdvised(ep));
@@ -1077,14 +1253,82 @@
new ClientConsumerDelegate(consumerID, binding.getQueue().getChannelID(),
prefetchSize, maxDeliveryAttempts);
- putConsumerEndpoint(consumerID, ep); // caching consumer locally
-
- connectionEndpoint.getServerPeer().putConsumerEndpoint(consumerID, ep); // cachin consumer in server peer
-
+ synchronized (consumers)
+ {
+ consumers.put(new Integer(consumerID), ep);
+ }
+
log.debug("created and registered " + ep);
return stub;
}
-
+
+ private void promptDelivery(Set channels)
+ {
+ //Now prompt delivery on the channels
+ Iterator iter = channels.iterator();
+
+ while (iter.hasNext())
+ {
+ DeliveryObserver observer = (DeliveryObserver)iter.next();
+
+ ((Channel)observer).deliver(false);
+ }
+ }
+
+
// Inner classes -------------------------------------------------
+
+ /**
+ *
+ * The purpose of this class is to remove deliveries from the delivery list on commit
+ * Each transaction has once instance of this per SCE
+ *
+ */
+ private class DeliveryCallback implements TxCallback
+ {
+ List delList = new ArrayList();
+
+ public void beforePrepare()
+ {
+ //NOOP
+ }
+
+ public void beforeCommit(boolean onePhase)
+ {
+ //NOOP
+ }
+
+ public void beforeRollback(boolean onePhase)
+ {
+ //NOOP
+ }
+
+ public void afterPrepare()
+ {
+ //NOOP
+ }
+
+ public synchronized void afterCommit(boolean onePhase) throws TransactionException
+ {
+ // Remove the deliveries from the delivery map.
+ Iterator iter = delList.iterator();
+ while (iter.hasNext())
+ {
+ Long deliveryId = (Long)iter.next();
+
+ deliveries.remove(deliveryId);
+ }
+ }
+
+ public void afterRollback(boolean onePhase) throws TransactionException
+ {
+ //NOOP
+ }
+
+ synchronized void addDeliveryId(Long deliveryId)
+ {
+ delList.add(deliveryId);
+ }
+ }
}
Modified: trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -33,7 +33,6 @@
import org.jboss.jms.destination.JBossQueue;
import org.jboss.jms.destination.JBossTopic;
import org.jboss.jms.message.JBossMessage;
-import org.jboss.jms.tx.AckInfo;
/**
* @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
@@ -73,14 +72,14 @@
* @param ackInfos
* @throws JMSException
*/
- void acknowledgeBatch(List ackInfos) throws JMSException;
+ void acknowledgeBatch(List deliveryIds) throws JMSException;
/**
* Acknowledge a message - used for auto acknowledge
- * @param ackInfo
+ * @param deliveryId
* @throws JMSException
*/
- void acknowledge(AckInfo ackInfo) throws JMSException;
+ void acknowledge(Ack ack) throws JMSException;
/**
* Add a temporary destination.
@@ -114,15 +113,14 @@
* or at session recovery to cancel any messages that couldn't be redelivered locally
* @param ackInfos
*/
- void cancelDeliveries(List ackInfos) throws JMSException;
-
-
+ void cancelDeliveries(List cancelInfos) throws JMSException;
+
/**
- * Send a list of unacked ackInfos to the server so the delivery lists can be repopulated
+ * Send delivery info to the server so the delivery lists can be repopulated
* used at failover
* @param ackInfos
* @throws JMSException
*/
- void sendUnackedAckInfos(List ackInfos) throws JMSException;
+ void recoverDeliveries(List createInfos) throws JMSException;
}
Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -65,11 +65,6 @@
endpoint.closing();
}
- public boolean isClosed()
- {
- return endpoint.isClosed();
- }
-
public boolean hasNextMessage() throws JMSException
{
return endpoint.hasNextMessage();
@@ -84,6 +79,11 @@
{
return endpoint.nextMessageBlock(maxMessages);
}
+
+ public boolean isClosed() throws JMSException
+ {
+ return endpoint.isClosed();
+ }
// AdvisedSupport overrides --------------------------------------
Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -67,11 +67,6 @@
endpoint.closing();
}
- public boolean isClosed()
- {
- return endpoint.isClosed();
- }
-
public SessionDelegate createSessionDelegate(boolean transacted,
int acknowledgmentMode,
boolean isXA) throws JMSException
@@ -108,6 +103,11 @@
{
return endpoint.getPreparedTransactions();
}
+
+ public boolean isClosed() throws JMSException
+ {
+ return endpoint.isClosed();
+ }
// Public --------------------------------------------------------
Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -64,11 +64,6 @@
endpoint.closing();
}
- public boolean isClosed()
- {
- return endpoint.isClosed();
- }
-
public void more() throws JMSException
{
endpoint.more();
@@ -78,6 +73,11 @@
{
endpoint.confirmDelivery(count);
}
+
+ public boolean isClosed() throws JMSException
+ {
+ return endpoint.isClosed();
+ }
// AdvisedSupport overrides --------------------------------------
Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -31,8 +31,8 @@
import org.jboss.jms.destination.JBossQueue;
import org.jboss.jms.destination.JBossTopic;
import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.server.endpoint.Ack;
import org.jboss.jms.server.endpoint.SessionEndpoint;
-import org.jboss.jms.tx.AckInfo;
/**
* The server-side advised instance corresponding to a Session. It is bound to the AOP
@@ -74,11 +74,6 @@
endpoint.closing();
}
- public boolean isClosed()
- {
- return endpoint.isClosed();
- }
-
public void send(JBossMessage msg) throws JMSException
{
endpoint.send(msg);
@@ -107,12 +102,12 @@
return endpoint.createTopic(topicName);
}
- public void acknowledgeBatch(List ackInfos) throws JMSException
+ public void acknowledgeBatch(List acks) throws JMSException
{
- endpoint.acknowledgeBatch(ackInfos);
+ endpoint.acknowledgeBatch(acks);
}
- public void acknowledge(AckInfo ack) throws JMSException
+ public void acknowledge(Ack ack) throws JMSException
{
endpoint.acknowledge(ack);
}
@@ -137,11 +132,16 @@
endpoint.cancelDeliveries(ackInfos);
}
- public void sendUnackedAckInfos(List ackInfos) throws JMSException
+ public void recoverDeliveries(List ackInfos) throws JMSException
{
- endpoint.sendUnackedAckInfos(ackInfos);
+ endpoint.recoverDeliveries(ackInfos);
}
+ public boolean isClosed() throws JMSException
+ {
+ return endpoint.isClosed();
+ }
+
// AdvisedSupport overrides --------------------------------------
Modified: trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -42,8 +42,11 @@
import org.jboss.jms.message.JBossMessage;
import org.jboss.jms.server.ServerPeer;
import org.jboss.jms.server.Version;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.Cancel;
import org.jboss.jms.server.endpoint.ClientDelivery;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryRecovery;
import org.jboss.jms.tx.TransactionRequest;
import org.jboss.logging.Logger;
import org.jboss.messaging.core.message.MessageFactory;
@@ -95,7 +98,8 @@
protected static final byte MORE = 5;
protected static final byte SEND_TRANSACTION = 6;
protected static final byte GET_ID_BLOCK = 7;
- protected static final byte UNACKED_ACKINFOS = 8;
+ protected static final byte RECOVER_DELIVERIES = 8;
+ protected static final byte CONFIRM_DELIVERY = 9;
// The response codes - start from 100
@@ -233,9 +237,9 @@
writeHeader(mi, dos);
- AckInfo ack = (AckInfo)mi.getArguments()[0];
+ Ack ack = (Ack)mi.getArguments()[0];
- ack.write(dos);
+ dos.writeLong(ack.getDeliveryId());
dos.flush();
@@ -255,8 +259,8 @@
while (iter.hasNext())
{
- AckInfo ack = (AckInfo)iter.next();
- ack.write(dos);
+ Ack ack = (Ack)iter.next();
+ dos.writeLong(ack.getDeliveryId());
}
dos.flush();
@@ -305,17 +309,17 @@
while (iter.hasNext())
{
- AckInfo ack = (AckInfo)iter.next();
- ack.write(dos);
+ Cancel cancel = (Cancel)iter.next();
+ cancel.write(dos);
}
dos.flush();
if (trace) { log.trace("wrote cancelDeliveries()"); }
}
- else if ("sendUnackedAckInfos".equals(methodName) && mi.getArguments() != null)
+ else if ("recoverDeliveries".equals(methodName) && mi.getArguments() != null)
{
- dos.writeByte(UNACKED_ACKINFOS);
+ dos.writeByte(RECOVER_DELIVERIES);
writeHeader(mi, dos);
@@ -327,14 +331,28 @@
while (iter.hasNext())
{
- AckInfo ack = (AckInfo)iter.next();
- ack.write(dos);
+ DeliveryRecovery d = (DeliveryRecovery)iter.next();
+ d.write(dos);
}
dos.flush();
if (trace) { log.trace("wrote sendUnackedAckInfos()"); }
}
+ else if ("confirmDelivery".equals(methodName))
+ {
+ dos.writeByte(CONFIRM_DELIVERY);
+
+ writeHeader(mi, dos);
+
+ Integer count = (Integer)mi.getArguments()[0];
+
+ dos.writeInt(count.intValue());
+
+ dos.flush();
+
+ if (trace) { log.trace("wrote confirmDelivery()"); }
+ }
else
{
dos.write(SERIALIZED);
@@ -483,14 +501,6 @@
// We don't use acknowledgeable push callbacks
-// Map payload = callback.getReturnPayload();
-// String guid = (String)payload.get(ServerInvokerCallbackHandler.CALLBACK_ID);
-// dos.writeUTF(guid);
-// String listenerId = (String)payload.get(Client.LISTENER_ID_KEY);
-// dos.writeUTF(listenerId);
-// String acks = (String)payload.get(ServerInvokerCallbackHandler.REMOTING_ACKNOWLEDGES_PUSH_CALLBACKS);
-// dos.writeUTF(acks);
-
MessagingMarshallable mm = (MessagingMarshallable)callback.getParameter();
ClientDelivery delivery = (ClientDelivery)mm.getLoad();
delivery.write(dos);
@@ -649,11 +659,9 @@
{
MethodInvocation mi = readHeader(dis);
- AckInfo info = new AckInfo();
+ long l = dis.readLong();
- info.read(dis);
-
- Object[] args = new Object[] {info};
+ Object[] args = new Object[] {new DefaultAck(l)};
mi.setArguments(args);
@@ -675,11 +683,9 @@
for (int i = 0; i < num; i++)
{
- AckInfo ack = new AckInfo();
+ long l = dis.readLong();
- ack.read(dis);
-
- acks.add(ack);
+ acks.add(new DefaultAck(l));
}
Object[] args = new Object[] {acks};
@@ -704,11 +710,11 @@
for (int i = 0; i < size; i++)
{
- AckInfo ack = new AckInfo();
+ Cancel cancel = new Cancel();
- ack.read(dis);
+ cancel.read(dis);
- acks.add(ack);
+ acks.add(cancel);
}
Object[] args = new Object[] {acks};
@@ -723,24 +729,24 @@
return request;
}
- case UNACKED_ACKINFOS:
+ case RECOVER_DELIVERIES:
{
MethodInvocation mi = readHeader(dis);
int size = dis.readInt();
- List acks = new ArrayList(size);
+ List dels = new ArrayList(size);
for (int i = 0; i < size; i++)
{
- AckInfo ack = new AckInfo();
+ DeliveryRecovery d = new DeliveryRecovery();
- ack.read(dis);
+ d.read(dis);
- acks.add(ack);
+ dels.add(d);
}
- Object[] args = new Object[] {acks};
+ Object[] args = new Object[] {dels};
mi.setArguments(args);
@@ -752,6 +758,24 @@
return request;
}
+ case CONFIRM_DELIVERY:
+ {
+ MethodInvocation mi = readHeader(dis);
+
+ int count = dis.readInt();
+
+ Object[] args = new Object[] {new Integer(count)};
+
+ mi.setArguments(args);
+
+ InvocationRequest request =
+ new InvocationRequest(null, ServerPeer.REMOTING_JMS_SUBSYSTEM,
+ new MessagingMarshallable(version, mi), null, null, null);
+
+ if (trace) { log.trace("read confirmDelivery()"); }
+
+ return request;
+ }
case ID_BLOCK_RESPONSE:
{
IdBlock block = new IdBlock();
@@ -852,18 +876,11 @@
{
// We don't use acknowledgeable push callbacks
-// String guid = dis.readUTF();
-// String listenerId = dis.readUTF();
-// String acks = dis.readUTF();
ClientDelivery delivery = new ClientDelivery();
delivery.read(dis);
MessagingMarshallable mm = new MessagingMarshallable(version, delivery);
Callback callback = new Callback(mm);
-// HashMap payload = new HashMap();
-// payload.put(ServerInvokerCallbackHandler.CALLBACK_ID, guid);
-// payload.put(Client.LISTENER_ID_KEY, listenerId);
-// payload.put(ServerInvokerCallbackHandler.REMOTING_ACKNOWLEDGES_PUSH_CALLBACKS, acks);
-// callback.setReturnPayload(payload);
+
callbackList.add(callback);
}
Deleted: trunk/src/main/org/jboss/jms/tx/AckInfo.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/AckInfo.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/AckInfo.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -1,147 +0,0 @@
-/*
- * 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.jms.tx;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-
-import org.jboss.jms.message.MessageProxy;
-import org.jboss.messaging.util.Streamable;
-
-/**
- * Struct like class for holding information regarding an acknowledgement to be passed to the server
- * for processing.
- *
- * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
- * @author <a href="mailto:ovidiu at jboss.com>Ovidiu Feodorov</a>
- *
- * $Id$
- */
-public class AckInfo implements Streamable
-{
- // Constants -----------------------------------------------------
-
- // Attributes ----------------------------------------------------
-
- protected long messageID;
- protected int consumerID;
- protected int deliveryCount;
-
- protected MessageProxy msg;
-
- // Static --------------------------------------------------------
-
- // Constructors --------------------------------------------------
-
- public AckInfo()
- {
- }
-
- public AckInfo(MessageProxy proxy, int consumerID)
- {
- this.msg = proxy;
- this.messageID = proxy.getMessage().getMessageID();
- this.consumerID = consumerID;
- }
-
- //Only used for testing
- public AckInfo(long messageID, int consumerID, int deliveryCount)
- {
- this.messageID = messageID;
- this.consumerID = consumerID;
- this.deliveryCount = deliveryCount;
- }
-
- // Public --------------------------------------------------------
-
- public long getMessageID()
- {
- return messageID;
- }
-
- public int getConsumerID()
- {
- return consumerID;
- }
-
- /** Used to change ack's id during failover */
- public void setConsumerID(int consumerID)
- {
- this.consumerID = consumerID;
- }
-
- public MessageProxy getMessage()
- {
- return msg;
- }
-
- public int getDeliveryCount()
- {
- if (msg == null)
- {
- return deliveryCount;
- }
- else
- {
- return msg.getDeliveryCount();
- }
- }
-
- public String toString()
- {
- return "AckInfo[" + messageID + ", " + consumerID + "]";
- }
-
- // Streamable implementation ---------------------------------
-
- public void write(DataOutputStream out) throws Exception
- {
- out.writeLong(messageID);
- out.writeInt(consumerID);
- if (msg != null)
- {
- out.writeInt(msg.getDeliveryCount());
- }
- else
- {
- out.writeInt(deliveryCount);
- }
- }
-
- public void read(DataInputStream in) throws Exception
- {
- messageID = in.readLong();
- consumerID = in.readInt();
- deliveryCount = in.readInt();
- }
-
- // Class YYY overrides -------------------------------------------
-
- // Protected -----------------------------------------------------
-
- // Package Private -----------------------------------------------
-
- // Private -------------------------------------------------------
-
- // Inner Classes -------------------------------------------------
-
-}
Copied: trunk/src/main/org/jboss/jms/tx/ClientTransaction.java (from rev 1783, trunk/src/main/org/jboss/jms/tx/TxState.java)
===================================================================
--- trunk/src/main/org/jboss/jms/tx/TxState.java 2006-12-13 09:46:39 UTC (rev 1783)
+++ trunk/src/main/org/jboss/jms/tx/ClientTransaction.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,391 @@
+/*
+ * 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.jms.tx;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.jms.client.state.SessionState;
+import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
+import org.jboss.messaging.core.message.MessageFactory;
+
+/**
+ * Holds the state of a transaction on the client side
+ *
+ * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
+ */
+public class ClientTransaction
+{
+ // Constants -----------------------------------------------------
+
+ public final static byte TX_OPEN = 0;
+
+ public final static byte TX_ENDED = 1;
+
+ public final static byte TX_PREPARED = 2;
+
+ public final static byte TX_COMMITED = 3;
+
+ public final static byte TX_ROLLEDBACK = 4;
+
+ // Attributes ----------------------------------------------------
+
+ private int state = TX_OPEN;
+
+ //Maintained on the client side
+ private Map sessionStatesMap;
+
+ //Read from on the server side
+ private List sessionStatesList;
+
+ private boolean clientSide;
+
+ // Static --------------------------------------------------------
+
+ // Constructors --------------------------------------------------
+
+ public ClientTransaction()
+ {
+ clientSide = true;
+ }
+
+ // Public --------------------------------------------------------
+
+ public int getState()
+ {
+ return state;
+ }
+
+ public void addMessage(int sessionId, JBossMessage msg)
+ {
+ if (!clientSide)
+ {
+ throw new IllegalStateException("Cannot call this method on the server side");
+ }
+ SessionTxState sessionTxState = getSessionTxState(sessionId);
+
+ sessionTxState.addMessage(msg);
+ }
+
+ public void addAck(int sessionId, DeliveryInfo info)
+ {
+ if (!clientSide)
+ {
+ throw new IllegalStateException("Cannot call this method on the server side");
+ }
+ SessionTxState sessionTxState = getSessionTxState(sessionId);
+
+ sessionTxState.addAck(info);
+ }
+
+ public void clearMessages()
+ {
+ if (!clientSide)
+ {
+ throw new IllegalStateException("Cannot call this method on the server side");
+ }
+ Iterator iter = sessionStatesMap.values().iterator();
+
+ while (iter.hasNext())
+ {
+ SessionTxState sessionTxState = (SessionTxState)iter.next();
+
+ sessionTxState.clearMessages();
+ }
+ }
+
+ public void setState(int state)
+ {
+ if (!clientSide)
+ {
+ throw new IllegalStateException("Cannot call this method on the server side");
+ }
+ this.state = state;
+ }
+
+ public Collection getSessionStates()
+ {
+ if (sessionStatesList != null)
+ {
+ return sessionStatesList;
+ }
+ else
+ {
+ return sessionStatesMap.values();
+ }
+ }
+
+ /*
+ * Substitute newSessionId for oldSessionId
+ */
+ public void handleFailover(Map oldNewSessionMap)
+ {
+ if (!clientSide)
+ {
+ throw new IllegalStateException("Cannot call this method on the server side");
+ }
+ //Note we have to do this in one go since there may be overlap between old and new session ids
+ //and we don't want to overwrite keys in the map
+
+ if (sessionStatesMap != null)
+ {
+ Map newMap = new HashMap();
+
+ Iterator iter = oldNewSessionMap.entrySet().iterator();
+
+ while (iter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry)iter.next();
+
+ Integer oldSessionId = (Integer)entry.getKey();
+
+ SessionState newSessionState = (SessionState)entry.getValue();
+
+ int newSessionId = newSessionState.getSessionId();
+
+ SessionTxState state = (SessionTxState)sessionStatesMap.get(oldSessionId);
+
+ if (state != null)
+ {
+ state.handleFailover(newSessionId);
+ }
+
+ newMap.put(new Integer(newSessionId), state);
+
+ }
+
+ sessionStatesMap = newMap;
+ }
+ }
+
+ public List getDeliveriesForSession(int sessionId)
+ {
+ if (!clientSide)
+ {
+ throw new IllegalStateException("Cannot call this method on the server side");
+ }
+ SessionTxState state = getSessionTxState(sessionId);
+
+ if (state != null)
+ {
+ return state.getAcks();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // Streamable implementation ---------------------------------
+
+ public void write(DataOutputStream out) throws Exception
+ {
+ out.writeInt(state);
+
+ out.writeInt(sessionStatesMap.size());
+
+ Iterator iter = sessionStatesMap.values().iterator();
+
+ while (iter.hasNext())
+ {
+ SessionTxState state = (SessionTxState)iter.next();
+
+ out.writeInt(state.getSessionId());
+
+ List msgs = state.getMsgs();
+
+ out.writeInt(msgs.size());
+
+ Iterator iter2 = msgs.iterator();
+
+ while (iter2.hasNext())
+ {
+ JBossMessage m = (JBossMessage)iter2.next();
+
+ out.writeByte(m.getType());
+
+ m.write(out);
+ }
+
+ List acks = state.getAcks();
+
+ out.writeInt(acks.size());
+
+ iter2 = acks.iterator();
+
+ while (iter2.hasNext())
+ {
+ DeliveryInfo ack = (DeliveryInfo)iter2.next();
+
+ //We only need the delivery id written
+ out.writeLong(ack.getMessageProxy().getDeliveryId());
+ }
+ }
+ }
+
+
+ public void read(DataInputStream in) throws Exception
+ {
+ clientSide = false;
+
+ state = in.readInt();
+
+ int numSessions = in.readInt();
+
+ //Read in as a list since we don't want the extra overhead of putting into a map
+ //which won't be used on the server side
+ sessionStatesList = new ArrayList(numSessions);
+
+ for (int i = 0; i < numSessions; i++)
+ {
+ int sessionId = in.readInt();
+
+ SessionTxState sessionState = new SessionTxState(sessionId);
+
+ sessionStatesList.add(sessionState);
+
+ int numMsgs = in.readInt();
+
+ for (int j = 0; j < numMsgs; j++)
+ {
+ byte type = in.readByte();
+
+ JBossMessage msg = (JBossMessage)MessageFactory.createMessage(type);
+
+ msg.read(in);
+
+ sessionState.addMessage(msg);
+ }
+
+ int numAcks = in.readInt();
+
+ for (int j = 0; j < numAcks; j++)
+ {
+ long ack = in.readLong();
+
+ sessionState.addAck(new DefaultAck(ack));
+ }
+ }
+ }
+
+ // Protected -----------------------------------------------------
+
+ // Package Private -----------------------------------------------
+
+ // Private -------------------------------------------------------
+
+ private SessionTxState getSessionTxState(int sessionId)
+ {
+ if (sessionStatesMap == null)
+ {
+ sessionStatesMap = new HashMap();
+ }
+
+ SessionTxState sessionTxState = (SessionTxState)sessionStatesMap.get(new Integer(sessionId));
+
+ if (sessionTxState == null)
+ {
+ sessionTxState = new SessionTxState(sessionId);
+
+ sessionStatesMap.put(new Integer(sessionId), sessionTxState);
+ }
+
+ return sessionTxState;
+ }
+
+
+
+ // Inner Classes -------------------------------------------------
+
+ public class SessionTxState
+ {
+ SessionTxState(int sessionId)
+ {
+ this.sessionId = sessionId;
+ }
+
+ void addMessage(JBossMessage msg)
+ {
+ msgs.add(msg);
+ }
+
+ void addAck(Ack ack)
+ {
+ acks.add(ack);
+ }
+
+ public List getMsgs()
+ {
+ return msgs;
+ }
+
+ public List getAcks()
+ {
+ return acks;
+ }
+
+ public int getSessionId()
+ {
+ return sessionId;
+ }
+
+ void handleFailover(int newSessionId)
+ {
+ this.sessionId = newSessionId;
+
+ //Remove any non persistent acks
+
+ Iterator iter = acks.iterator();
+
+ while (iter.hasNext())
+ {
+ DeliveryInfo info = (DeliveryInfo)iter.next();
+
+ if (!info.getMessageProxy().getMessage().isReliable())
+ {
+ iter.remove();
+ }
+ }
+ }
+
+ void clearMessages()
+ {
+ msgs.clear();
+ }
+
+ private int sessionId;
+
+ private List msgs = new ArrayList();
+
+ private List acks = new ArrayList();
+ }
+
+}
Modified: trunk/src/main/org/jboss/jms/tx/ResourceManager.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/ResourceManager.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/ResourceManager.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -22,16 +22,13 @@
package org.jboss.jms.tx;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.jms.IllegalStateException;
import javax.jms.JMSException;
-import javax.jms.Message;
import javax.jms.TransactionRolledBackException;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
@@ -39,6 +36,10 @@
import org.jboss.jms.delegate.ConnectionDelegate;
import org.jboss.jms.delegate.SessionDelegate;
+import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.message.MessageProxy;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
+import org.jboss.jms.tx.ClientTransaction.SessionTxState;
import org.jboss.jms.util.MessagingTransactionRolledBackException;
import org.jboss.jms.util.MessagingXAException;
import org.jboss.logging.Logger;
@@ -66,7 +67,7 @@
private boolean trace = log.isTraceEnabled();
- protected ConcurrentHashMap transactions = new ConcurrentHashMap();
+ private ConcurrentHashMap transactions = new ConcurrentHashMap();
// Static --------------------------------------------------------
@@ -76,24 +77,20 @@
// Public --------------------------------------------------------
- public TxState getTx(Object xid)
+ /**
+ * Remove a tx
+ */
+ public ClientTransaction removeTx(Object xid)
{
- if (trace) { log.trace("getting transaction for " + xid); }
-
- return (TxState)transactions.get(xid);
+ return removeTxInternal(xid);
}
-
- public TxState removeTx(Object xid)
- {
- return (TxState)transactions.remove(xid);
- }
-
+
/**
* Create a local tx.
*/
public LocalTx createLocalTx()
{
- TxState tx = new TxState();
+ ClientTransaction tx = new ClientTransaction();
LocalTx xid = getNextTxId();
@@ -108,70 +105,58 @@
* @param xid - The id of the transaction to add the message to
* @param m The message
*/
- public void addMessage(Object xid, Message m)
+ public void addMessage(Object xid, int sessionId, JBossMessage msg)
{
if (trace) { log.trace("addding message for xid " + xid); }
- TxState tx = getTx(xid);
+ ClientTransaction tx = getTxInternal(xid);
- tx.getMessages().add(m);
+ tx.addMessage(sessionId, msg);
}
-
- /**
- * Navigate on ACK and change consumer ids on every ACK not sent yet.
- */
- public void handleFailover(int oldConsumerID, int newConsumerID)
- {
- if (trace) { log.trace("handleFailover:: Transfering consumer id on ACKs from " + oldConsumerID + " to " + newConsumerID); }
-
- //TODO need to lock the rm while this is happening
-
- //Note we need to replace ids for *all* transactions - this is because, for XA
- //the session might have done work in many transactions
- Iterator iter = this.transactions.values().iterator();
-
- while (iter.hasNext())
- {
- TxState tx = (TxState)iter.next();
-
- tx.handleFailover(oldConsumerID, newConsumerID);
- }
- }
-
- /*
- * Get all the ackinfos with a consumer id in the specified set
- */
- public List getAckInfosForConsumerIds(Set consumerIds)
- {
- Iterator iter = this.transactions.values().iterator();
-
- List ackInfos = new ArrayList();
-
- while (iter.hasNext())
- {
- TxState tx = (TxState)iter.next();
-
- tx.getAckInfosForConsumerIds(ackInfos, consumerIds);
- }
-
- return ackInfos;
- }
-
- public void removeNonPersistentAcks(Set consumerIds)
- {
- Iterator iter = this.transactions.values().iterator();
-
- List ackInfos = new ArrayList();
-
- while (iter.hasNext())
- {
- TxState tx = (TxState)iter.next();
-
- tx.removeNonPersistentAcks(consumerIds);
- }
- }
-
+ /*
+ * Failover session from old session -> new session
+ * This basically involves updating the session id
+ */
+ public void handleFailover(Map oldNewSessionMap)
+ {
+ //Note we need to replace ids for *all* transactions - this is because, for XA
+ //the session might have done work in many transactions
+ Iterator iter = this.transactions.values().iterator();
+
+ while (iter.hasNext())
+ {
+ ClientTransaction tx = (ClientTransaction)iter.next();
+
+ tx.handleFailover(oldNewSessionMap);
+ }
+ }
+
+ /*
+ * Get all the deliveries corresponding to the session id
+ */
+ public List getDeliveriesForSession(int sessionId)
+ {
+ Iterator iter = this.transactions.values().iterator();
+
+ List ackInfos = new ArrayList();
+
+ while (iter.hasNext())
+ {
+ ClientTransaction tx = (ClientTransaction)iter.next();
+
+ List acks = tx.getDeliveriesForSession(sessionId);
+
+ if (acks != null)
+ {
+ ackInfos.addAll(acks);
+ }
+ }
+
+ return ackInfos;
+ }
+
+
/**
* Add an acknowledgement to the transaction
*
@@ -180,25 +165,25 @@
* @param sessionState - the session the ack is in - we need this so on rollback we can tell each session
* to redeliver it's messages
*/
- public void addAck(Object xid, AckInfo ackInfo) throws JMSException
+ public void addAck(Object xid, int sessionId, DeliveryInfo ackInfo) throws JMSException
{
if (trace) { log.trace("adding " + ackInfo + " to transaction " + xid); }
- TxState tx = getTx(xid);
+ ClientTransaction tx = getTxInternal(xid);
if (tx == null)
{
throw new JMSException("There is no transaction with id " + xid);
}
- tx.getAcks().add(ackInfo);
+ tx.addAck(sessionId, ackInfo);
}
public void commitLocal(LocalTx xid, ConnectionDelegate connection) throws JMSException
{
if (trace) { log.trace("commiting local xid " + xid); }
- TxState tx = this.getTx(xid);
+ ClientTransaction tx = this.getTxInternal(xid);
//Invalid xid
if (tx == null)
@@ -215,7 +200,7 @@
//If we get this far we can remove the transaction
- this.removeTx(xid);
+ this.removeTxInternal(xid);
}
catch (Throwable t)
{
@@ -233,7 +218,7 @@
{
if (trace) { log.trace("rolling back local xid " + xid); }
- TxState ts = removeTx(xid);
+ ClientTransaction ts = removeTxInternal(xid);
if (ts == null)
{
@@ -241,6 +226,7 @@
}
// don't need messages for rollback
+ // We don't clear the acks since we need to redeliver locally
ts.clearMessages();
// for one phase rollback there is nothing to do on the server
@@ -248,11 +234,27 @@
redeliverMessages(ts);
}
- public void commit(Xid xid, boolean onePhase, ConnectionDelegate connection) throws XAException
+ //Only used for testing
+ public ClientTransaction getTx(Object xid)
{
+ return getTxInternal(xid);
+ }
+
+ //Only used for testing
+ public int size()
+ {
+ return transactions.size();
+ }
+
+ // Protected ------------------------------------------------------
+
+ // Package Private ------------------------------------------------
+
+ void commit(Xid xid, boolean onePhase, ConnectionDelegate connection) throws XAException
+ {
if (trace) { log.trace("commiting xid " + xid + ", onePhase=" + onePhase); }
- TxState tx = removeTx(xid);
+ ClientTransaction tx = removeTxInternal(xid);
if (onePhase)
{
@@ -273,7 +275,7 @@
{
if (tx != null)
{
- if (tx.getState() != TxState.TX_PREPARED)
+ if (tx.getState() != ClientTransaction.TX_PREPARED)
{
throw new MessagingXAException(XAException.XAER_PROTO, "commit called for transaction, but it is not prepared");
}
@@ -295,25 +297,26 @@
if (tx != null)
{
- tx.setState(TxState.TX_COMMITED);
+ tx.setState(ClientTransaction.TX_COMMITED);
}
}
- public void rollback(Xid xid, ConnectionDelegate connection) throws XAException
+ void rollback(Xid xid, ConnectionDelegate connection) throws XAException
{
if (trace) { log.trace("rolling back xid " + xid); }
- TxState tx = removeTx(xid);
+ ClientTransaction tx = removeTxInternal(xid);
TransactionRequest request = null;
// we don't need to send the messages to the server on a rollback
if (tx != null)
{
+ //We don't clear the acks since we need to redeliver locally
tx.clearMessages();
}
- if ((tx == null) || tx.getState() == TxState.TX_PREPARED)
+ if ((tx == null) || tx.getState() == ClientTransaction.TX_PREPARED)
{
request = new TransactionRequest(TransactionRequest.TWO_PHASE_ROLLBACK_REQUEST, xid, tx);
@@ -339,78 +342,25 @@
}
}
-
- /*
- * Rollback has occurred so we need to redeliver any unacked messages corresponding to the acks
- * is in the transaction.
- */
- private void redeliverMessages(TxState ts) throws JMSException
+ void endTx(Xid xid, boolean success) throws XAException
{
- // Sort messages into lists, one for each session. We use a LinkedHashMap since we need to
- // preserve the order of the sessions.
-
- Map toAck = new LinkedHashMap();
-
- for(Iterator i = ts.getAcks().iterator(); i.hasNext(); )
- {
- AckInfo ack = (AckInfo)i.next();
- SessionDelegate del = ack.msg.getSessionDelegate();
-
- List acks = (List)toAck.get(del);
- if (acks == null)
- {
- acks = new ArrayList();
- toAck.put(del, acks);
- }
- acks.add(ack);
- }
-
- // Now tell each session to redeliver.
-
- LinkedList l = new LinkedList();
-
- for(Iterator i = toAck.entrySet().iterator(); i.hasNext();)
- {
- // need to reverse the order
- Object entry = i.next();
- l.addFirst(entry);
- }
-
- for(Iterator i = l.iterator(); i.hasNext();)
- {
- Map.Entry entry = (Map.Entry)i.next();
- SessionDelegate sess = (SessionDelegate)entry.getKey();
- List acks = (List)entry.getValue();
- sess.redeliver(acks);
- }
- }
-
- public int size()
- {
- return transactions.size();
- }
-
- // Protected ------------------------------------------------------
-
- protected void endTx(Xid xid, boolean success) throws XAException
- {
if (trace) { log.trace("ending " + xid + ", success=" + success); }
- TxState state = getTx(xid);
+ ClientTransaction state = getTxInternal(xid);
if (state == null)
{
throw new MessagingXAException(XAException.XAER_NOTA, "Cannot find transaction with xid:" + xid);
}
- state.setState(TxState.TX_ENDED);
+ state.setState(ClientTransaction.TX_ENDED);
}
- protected Xid joinTx(Xid xid) throws XAException
+ Xid joinTx(Xid xid) throws XAException
{
if (trace) { log.trace("joining " + xid); }
- TxState state = getTx(xid);
+ ClientTransaction state = getTxInternal(xid);
if (state == null)
{
@@ -420,11 +370,11 @@
return xid;
}
- protected int prepare(Xid xid, ConnectionDelegate connection) throws XAException
+ int prepare(Xid xid, ConnectionDelegate connection) throws XAException
{
if (trace) { log.trace("preparing " + xid); }
- TxState state = getTx(xid);
+ ClientTransaction state = getTxInternal(xid);
if (state == null)
{
@@ -436,16 +386,16 @@
sendTransactionXA(request, connection);
- state.setState(TxState.TX_PREPARED);
+ state.setState(ClientTransaction.TX_PREPARED);
return XAResource.XA_OK;
}
- protected Xid resumeTx(Xid xid) throws XAException
+ Xid resumeTx(Xid xid) throws XAException
{
if (trace) { log.trace("resuming " + xid); }
- TxState state = getTx(xid);
+ ClientTransaction state = getTxInternal(xid);
if (state == null)
{
@@ -455,11 +405,11 @@
return xid;
}
- protected Xid suspendTx(Xid xid) throws XAException
+ Xid suspendTx(Xid xid) throws XAException
{
if (trace) { log.trace("suspending " + xid); }
- TxState state = getTx(xid);
+ ClientTransaction state = getTxInternal(xid);
if (state == null)
{
@@ -469,48 +419,48 @@
return xid;
}
- protected Xid convertTx(LocalTx anonXid, Xid xid) throws XAException
+ Xid convertTx(LocalTx anonXid, Xid xid) throws XAException
{
if (trace) { log.trace("converting " + anonXid + " to " + xid); }
- TxState state = getTx(anonXid);
+ ClientTransaction state = getTxInternal(anonXid);
if (state == null)
{
throw new MessagingXAException(XAException.XAER_NOTA, "Cannot find transaction with xid:" + anonXid);
}
- state = getTx(xid);
+ state = getTxInternal(xid);
if (state != null)
{
throw new MessagingXAException(XAException.XAER_DUPID, "Transaction already exists:" + xid);
}
- TxState s = removeTx(anonXid);
+ ClientTransaction s = removeTxInternal(anonXid);
transactions.put(xid, s);
return xid;
}
- protected Xid startTx(Xid xid) throws XAException
+ Xid startTx(Xid xid) throws XAException
{
if (trace) { log.trace("starting " + xid); }
- TxState state = getTx(xid);
+ ClientTransaction state = getTxInternal(xid);
if (state != null)
{
throw new MessagingXAException(XAException.XAER_DUPID, "Transaction already exists with xid " + xid);
}
- transactions.put(xid, new TxState());
+ transactions.put(xid, new ClientTransaction());
return xid;
}
- protected Xid[] recover(int flags, ConnectionDelegate conn) throws XAException
+ Xid[] recover(int flags, ConnectionDelegate conn) throws XAException
{
if (trace) { log.trace("calling recover with flags: " + flags); }
@@ -532,10 +482,47 @@
}
}
- // Package Private ------------------------------------------------
-
// Private --------------------------------------------------------
+ private ClientTransaction getTxInternal(Object xid)
+ {
+ if (trace) { log.trace("getting transaction for " + xid); }
+
+ return (ClientTransaction)transactions.get(xid);
+ }
+
+ private ClientTransaction removeTxInternal(Object xid)
+ {
+ return (ClientTransaction)transactions.remove(xid);
+ }
+
+ /*
+ * Rollback has occurred so we need to redeliver any unacked messages corresponding to the acks
+ * is in the transaction.
+ */
+ private void redeliverMessages(ClientTransaction ts) throws JMSException
+ {
+ Collection sessionStates = ts.getSessionStates();
+
+ for (Iterator i = sessionStates.iterator(); i.hasNext();)
+ {
+ SessionTxState state = (SessionTxState)i.next();
+
+ List acks = state.getAcks();
+
+ if (!acks.isEmpty())
+ {
+ DeliveryInfo info = (DeliveryInfo)acks.get(0);
+
+ MessageProxy mp = info.getMessageProxy();
+
+ SessionDelegate del = mp.getSessionDelegate();
+
+ del.redeliver(acks);
+ }
+ }
+ }
+
private synchronized LocalTx getNextTxId()
{
return new LocalTx();
Modified: trunk/src/main/org/jboss/jms/tx/TransactionRequest.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/TransactionRequest.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/TransactionRequest.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -66,7 +66,7 @@
/** For 2 phase commit, this identifies the transaction. */
protected Xid xid;
- protected TxState state;
+ protected ClientTransaction state;
// Static --------------------------------------------------------
@@ -76,7 +76,7 @@
{
}
- public TransactionRequest(int requestType, Xid xid, TxState state)
+ public TransactionRequest(int requestType, Xid xid, ClientTransaction state)
{
this.requestType = requestType;
this.xid = xid;
@@ -153,7 +153,7 @@
}
else
{
- state = new TxState();
+ state = new ClientTransaction();
state.read(in);
}
@@ -161,7 +161,7 @@
// Public --------------------------------------------------------
- public TxState getState()
+ public ClientTransaction getState()
{
return state;
}
Deleted: trunk/src/main/org/jboss/jms/tx/TxState.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/TxState.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/TxState.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -1,224 +0,0 @@
-/*
- * 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.jms.tx;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.jboss.jms.message.JBossMessage;
-import org.jboss.messaging.core.message.MessageFactory;
-import org.jboss.messaging.util.Streamable;
-
-/**
- * Holds information for a JMS transaction to be sent to the server for
- * processing.
- * Holds the messages to be sent and the acknowledgements to be made
- * for the transaction
- *
- * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
- */
-public class TxState implements Streamable
-{
- // Constants -----------------------------------------------------
-
- public final static byte TX_OPEN = 0;
-
- public final static byte TX_ENDED = 1;
-
- public final static byte TX_PREPARED = 2;
-
- public final static byte TX_COMMITED = 3;
-
- public final static byte TX_ROLLEDBACK = 4;
-
- // Attributes ----------------------------------------------------
-
- protected int state = TX_OPEN;
-
- protected List messages = new ArrayList();
-
- protected List acks = new ArrayList();
-
- // Static --------------------------------------------------------
-
- // Constructors --------------------------------------------------
-
- public TxState()
- {
- }
-
- // Public --------------------------------------------------------
-
- public int getState()
- {
- return state;
- }
-
- public List getMessages()
- {
- return messages;
- }
-
- public List getAcks()
- {
- return acks;
- }
-
- public void clearMessages()
- {
- messages.clear();
- }
-
- public void setState(int state)
- {
- this.state = state;
- }
-
-
- /** Navigate on ACK and change consumer ids on every ACK not sent yet */
- public void handleFailover(int oldConsumerID, int newConsumerID)
- {
- for (Iterator ackIterator = acks.iterator(); ackIterator.hasNext(); )
- {
- AckInfo ackInfo = (AckInfo)ackIterator.next();
-
- if (ackInfo.getConsumerID() == oldConsumerID)
- {
- ackInfo.setConsumerID(newConsumerID);
- }
- }
- }
-
- public void getAckInfosForConsumerIds(List ackInfos, Set consumerIds)
- {
- for (Iterator ackIterator = acks.iterator(); ackIterator.hasNext(); )
- {
- AckInfo ackInfo = (AckInfo)ackIterator.next();
-
- if (consumerIds.contains(new Integer(ackInfo.getConsumerID())))
- {
- ackInfos.add(ackInfo);
- }
- }
- }
-
- public void removeNonPersistentAcks(Set consumerIds)
- {
- for (Iterator ackIterator = acks.iterator(); ackIterator.hasNext(); )
- {
- AckInfo ackInfo = (AckInfo)ackIterator.next();
-
- if (!ackInfo.msg.getMessage().isReliable())
- {
- ackIterator.remove();
- }
- }
- }
-
- // Streamable implementation ---------------------------------
-
- public void write(DataOutputStream out) throws Exception
- {
- out.writeInt(state);
- if (messages == null)
- {
- out.writeInt(-1);
- }
- else
- {
- out.writeInt(messages.size());
- Iterator iter = messages.iterator();
- while (iter.hasNext())
- {
- JBossMessage m = (JBossMessage)iter.next();
- //We don't use writeObject to avoid serialization overhead
- out.writeByte(m.getType());
- m.write(out);
- }
- }
- if (acks == null)
- {
- out.writeInt(-1);
- }
- else
- {
- out.writeInt(acks.size());
- Iterator iter = acks.iterator();
- while (iter.hasNext())
- {
- AckInfo a = (AckInfo)iter.next();
- //We don't use writeObject to avoid serialization overhead
- a.write(out);
- }
- }
- }
-
- public void read(DataInputStream in) throws Exception
- {
- state = in.readInt();
- int numMessages = in.readInt();
- if (numMessages == -1)
- {
- messages = null;
- }
- else
- {
- messages = new ArrayList(numMessages);
- for (int i = 0; i < numMessages; i++)
- {
- byte type = in.readByte();
- JBossMessage m = (JBossMessage)MessageFactory.createMessage(type);
- m.read(in);
- messages.add(m);
- }
- }
-
- int numAcks = in.readInt();
- if (numAcks == -1)
- {
- acks = null;
- }
- else
- {
- acks = new ArrayList(numAcks);
- for (int i = 0; i < numAcks; i++)
- {
- AckInfo info = new AckInfo();
- info.read(in);
- acks.add(info);
- }
- }
- }
-
- // Protected -----------------------------------------------------
-
- // Package Private -----------------------------------------------
-
- // Private -------------------------------------------------------
-
- // Inner Classes -------------------------------------------------
-
-}
Modified: trunk/tests/build.xml
===================================================================
--- trunk/tests/build.xml 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/build.xml 2006-12-14 19:32:42 UTC (rev 1794)
@@ -387,7 +387,7 @@
haltonerror="${junit.batchtest.haltonerror}">
<formatter type="plain" usefile="${junit.formatter.usefile}"/>
<fileset dir="${build.tests.classes}">
- <!-- <include name="**/messaging/core/**/*Test.class"/> -->
+ <include name="**/messaging/core/**/*Test.class"/>
<include name="**/messaging/jms/**/*Test.class"/>
<exclude name="**/jms/stress/**"/>
<exclude name="**/jms/crash/*Test.class"/>
Modified: trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -157,20 +157,14 @@
pub.publish(m);
sess.commit();
- log.info("sent messages");
-
//receive but rollback
TextMessage m2 = (TextMessage)sub.receive(3000);
-
- log.info("received");
-
+
assertNotNull(m2);
assertEquals("testing123", m2.getText());
sess.rollback();
- log.info("rolled back");
-
conn.close();
conn = cf.createTopicConnection();
conn.start();
@@ -262,7 +256,7 @@
}
}
- public void testTransactionalAcknowlegment() throws Exception
+ public void testTransactionalAcknowledgement() throws Exception
{
Connection conn = cf.createConnection();
@@ -328,7 +322,7 @@
{
m = consumer.receive();
log.trace("Received message " + i);
-
+
}
assertRemainingMessages(NUM_MESSAGES);
@@ -353,9 +347,8 @@
/**
* Send some messages, don't acknowledge them and verify that they are re-sent on recovery.
*/
- public void testClientAcknowledgeNoAcknowlegment() throws Exception
+ public void testClientAcknowledgeNoAcknowledgement() throws Exception
{
-
Connection conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -1203,7 +1196,10 @@
Thread.sleep(500);
ObjectName destObjectName =
new ObjectName("jboss.messaging.destination:service=Queue,name=Queue");
- Integer messageCount = (Integer)ServerManagement.getAttribute(destObjectName, "MessageCount");
+ Integer messageCount = (Integer)ServerManagement.getAttribute(destObjectName, "MessageCount");
+
+ log.trace("There are " + messageCount + " messages");
+
assertEquals(expected, messageCount.intValue());
return expected == messageCount.intValue();
}
Modified: trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -207,53 +207,64 @@
*/
public void testRedeliveryToCompetingConsumerOnQueue() throws Exception
{
- Connection conn = cf.createConnection();
+ Connection conn = null;
+
+ try
+ {
+ conn = cf.createConnection();
+
+ Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ MessageProducer prod = sessSend.createProducer(queue);
+
+ conn.start();
+
+ Session sessConsume1 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ MessageConsumer cons1 = sessConsume1.createConsumer(queue);
+
+ TextMessage tm = sessSend.createTextMessage();
+
+ tm.setText("Your mum");
+
+ prod.send(tm);
+
+ TextMessage tm2 = (TextMessage)cons1.receive();
+
+ assertNotNull(tm2);
+
+ assertEquals("Your mum", tm2.getText());
+
+ // Don't ack
+
+ // Create another consumer
+
+ Session sessConsume2 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+ MessageConsumer cons2 = sessConsume2.createConsumer(queue);
+
+ // this should cancel message and cause delivery to other consumer
+
+ log.trace("Closed session 1");
+ sessConsume1.close();
+
+ TextMessage tm3 = (TextMessage)cons2.receive(1000);
+
+ assertNotNull(tm3);
+
+ assertEquals("Your mum", tm3.getText());
+
+ tm3.acknowledge();
+ }
+ finally
+ {
- Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ if (conn != null)
+ {
+ conn.close();
+ }
+ }
- MessageProducer prod = sessSend.createProducer(queue);
-
- conn.start();
-
- Session sessConsume1 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
-
- MessageConsumer cons1 = sessConsume1.createConsumer(queue);
-
- TextMessage tm = sessSend.createTextMessage();
-
- tm.setText("Your mum");
-
- prod.send(tm);
-
- TextMessage tm2 = (TextMessage)cons1.receive();
-
- assertNotNull(tm2);
-
- assertEquals("Your mum", tm2.getText());
-
- // Don't ack
-
- // Create another consumer
-
- Session sessConsume2 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
-
- MessageConsumer cons2 = sessConsume2.createConsumer(queue);
-
- // this should cancel message and cause delivery to other consumer
-
- sessConsume1.close();
-
- TextMessage tm3 = (TextMessage)cons2.receive(1000);
-
- assertNotNull(tm3);
-
- assertEquals("Your mum", tm3.getText());
-
- tm3.acknowledge();
-
- conn.close();
-
-
}
Modified: trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -31,6 +31,7 @@
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -43,12 +44,16 @@
import org.jboss.jms.delegate.SessionDelegate;
import org.jboss.jms.message.JBossMessage;
import org.jboss.jms.message.MessageProxy;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.Cancel;
import org.jboss.jms.server.endpoint.ClientDelivery;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
import org.jboss.jms.server.remoting.JMSWireFormat;
import org.jboss.jms.server.remoting.MessagingMarshallable;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.tx.ClientTransaction;
import org.jboss.jms.tx.TransactionRequest;
-import org.jboss.jms.tx.TxState;
+import org.jboss.jms.tx.ClientTransaction.SessionTxState;
import org.jboss.logging.Logger;
import org.jboss.messaging.core.plugin.IdBlock;
import org.jboss.remoting.InvocationRequest;
@@ -130,11 +135,13 @@
sendMethod = sessionDelegate.getMethod("send", new Class[] { JBossMessage.class });
- acknowledgeMethod = sessionDelegate.getMethod("acknowledge", new Class[] { AckInfo.class });
+ acknowledgeMethod = sessionDelegate.getMethod("acknowledge", new Class[] { Ack.class });
acknowledgeBatchMethod = sessionDelegate.getMethod("acknowledgeBatch", new Class[] { java.util.List.class });
cancelDeliveriesMethod = sessionDelegate.getMethod("cancelDeliveries", new Class[] { java.util.List.class });
+
+ //TODO - this isn't complete - there are other methods to test
//Consumer
@@ -263,10 +270,8 @@
mi.getMetaData().addMetaData(Dispatcher.DISPATCHER, Dispatcher.OID, new Integer(objectId));
- long messageID = 123456;
- int consumerID = 65432;
- int deliveryCount = 765;
- AckInfo ack = new AckInfo(messageID, consumerID, deliveryCount);
+ int deliveryID = 765;
+ Ack ack = new DefaultAck(deliveryID);
Object[] args = new Object[] { ack };
@@ -304,15 +309,11 @@
//Next long should be methodHash
assertEquals(methodHash, dis.readLong());
- //Next should be the externalized AckInfo
- AckInfo ack2 = new AckInfo();
-
- ack2.read(dis);
+ //Next should be the deliveryid
+ long l = dis.readLong();
- assertEquals(ack.getMessageID(), ack2.getMessageID());
- assertEquals(ack.getConsumerID(), ack2.getConsumerID());
- assertEquals(ack.getDeliveryCount(), ack2.getDeliveryCount());
-
+ assertEquals(deliveryID, l);
+
//Now eos
try
{
@@ -340,10 +341,9 @@
assertEquals(objectId, ((Integer)mi2.getMetaData().getMetaData(Dispatcher.DISPATCHER, Dispatcher.OID)).intValue());
- AckInfo ack3 = (AckInfo)mi2.getArguments()[0];
+ Ack l2 = (Ack)mi2.getArguments()[0];
- assertEquals(ack3.getMessageID(), ack3.getMessageID());
- assertEquals(ack3.getConsumerID(), ack3.getConsumerID());
+ assertEquals(deliveryID, l2.getDeliveryId());
}
@@ -357,14 +357,16 @@
mi.getMetaData().addMetaData(Dispatcher.DISPATCHER, Dispatcher.OID, new Integer(objectId));
- AckInfo ackA = new AckInfo(1524, 71627, 32);
- AckInfo ackB = new AckInfo(987987, 45354, 21);
- AckInfo ackC = new AckInfo(32423, 4533, 6);
+ long ackA = 1343;
+ long ackB = 176276;
+
+ long ackC = 17261726;
+
List acks = new ArrayList();
- acks.add(ackA);
- acks.add(ackB);
- acks.add(ackC);
+ acks.add(new DefaultAck(ackA));
+ acks.add(new DefaultAck(ackB));
+ acks.add(new DefaultAck(ackC));
Object[] args = new Object[] { acks };
@@ -406,31 +408,17 @@
assertEquals(3, dis.readInt());
//Now the acks
- AckInfo ack = new AckInfo();
-
- ack.read(dis);
+ long l1 = dis.readLong();
- assertEquals(ackA.getMessageID(), ack.getMessageID());
- assertEquals(ackA.getConsumerID(), ack.getConsumerID());
- assertEquals(ackA.getDeliveryCount(), ack.getDeliveryCount());
+ long l2 = dis.readLong();
- ack = new AckInfo();
+ long l3 = dis.readLong();
- ack.read(dis);
+ assertEquals(ackA, l1);
+ assertEquals(ackB, l2);
+ assertEquals(ackC, l3);
- assertEquals(ackB.getMessageID(), ack.getMessageID());
- assertEquals(ackB.getConsumerID(), ack.getConsumerID());
- assertEquals(ackB.getDeliveryCount(), ack.getDeliveryCount());
- ack = new AckInfo();
-
- ack.read(dis);
-
- assertEquals(ackC.getMessageID(), ack.getMessageID());
- assertEquals(ackC.getConsumerID(), ack.getConsumerID());
- assertEquals(ackC.getDeliveryCount(), ack.getDeliveryCount());
-
-
//Now eos
try
{
@@ -462,14 +450,10 @@
assertEquals(3, acks.size());
- assertEquals(ackA.getMessageID(), ((AckInfo)(acks2.get(0))).getMessageID());
- assertEquals(ackA.getConsumerID(), ((AckInfo)(acks2.get(0))).getConsumerID());
+ assertEquals(ackA, ((DefaultAck)acks2.get(0)).getDeliveryId());
+ assertEquals(ackB, ((DefaultAck)acks2.get(1)).getDeliveryId());
+ assertEquals(ackC, ((DefaultAck)acks2.get(2)).getDeliveryId());
- assertEquals(ackB.getMessageID(), ((AckInfo)(acks2.get(1))).getMessageID());
- assertEquals(ackB.getConsumerID(), ((AckInfo)(acks2.get(1))).getConsumerID());
-
- assertEquals(ackC.getMessageID(), ((AckInfo)(acks2.get(2))).getMessageID());
- assertEquals(ackC.getConsumerID(), ((AckInfo)(acks2.get(2))).getConsumerID());
}
@@ -739,11 +723,19 @@
JBossMessage m = new JBossMessage(123);
MessageTest.configureMessage(m);
- AckInfo info = new AckInfo(123, 456, 66);
+ long deliveryId = 89281389;
- TxState state = new TxState();
- state.getMessages().add(m);
- state.getAcks().add(info);
+ int deliveryCount = 12;
+
+ MessageProxy proxy = JBossMessage.createThinDelegate(deliveryId, m, deliveryCount);
+
+ DeliveryInfo info = new DeliveryInfo(proxy, 76762, 98982);
+
+ int sessionId = 8787;
+
+ ClientTransaction state = new ClientTransaction();
+ state.addMessage(sessionId, m);
+ state.addAck(sessionId, info);
TransactionRequest request = new TransactionRequest(TransactionRequest.ONE_PHASE_COMMIT_REQUEST, null, state);
@@ -806,18 +798,24 @@
{
//Ok
}
+
+ ClientTransaction state2 = req.getState();
+
+ Collection sessionStates = state2.getSessionStates();
+
+ assertEquals(1, sessionStates.size());
+
+ SessionTxState sess = (SessionTxState)sessionStates.iterator().next();
- JBossMessage m2 = (JBossMessage)req.getState().getMessages().get(0);
+ JBossMessage m2 = (JBossMessage)sess.getMsgs().get(0);
MessageTest.ensureEquivalent(m, m2);
assertEquals(TransactionRequest.ONE_PHASE_COMMIT_REQUEST, req.getRequestType());
- AckInfo info2 = (AckInfo)req.getState().getAcks().get(0);
+ Ack ack = (Ack)sess.getAcks().get(0);
- assertEquals(info.getConsumerID(), info2.getConsumerID());
- assertEquals(info.getMessageID(), info2.getMessageID());
- assertEquals(info.getDeliveryCount(), info2.getDeliveryCount());
+ assertEquals(deliveryId, ack.getDeliveryId());
bis.reset();
@@ -837,17 +835,22 @@
TransactionRequest req2 = (TransactionRequest)mi2.getArguments()[0];
- JBossMessage m3 = (JBossMessage)req2.getState().getMessages().get(0);
+ ClientTransaction state3 = req2.getState();
+ Collection sessionStates2 = state3.getSessionStates();
+
+ SessionTxState sess2 = (SessionTxState)sessionStates2.iterator().next();
+
+ JBossMessage m3 = (JBossMessage)sess2.getMsgs().get(0);
+
MessageTest.ensureEquivalent(m, m3);
assertEquals(TransactionRequest.ONE_PHASE_COMMIT_REQUEST, req2.getRequestType());
- AckInfo info3 = (AckInfo)req2.getState().getAcks().get(0);
+ Ack ack2 = (Ack)sess2.getAcks().get(0);
- assertEquals(info.getConsumerID(), info3.getConsumerID());
- assertEquals(info.getMessageID(), info3.getMessageID());
-
+ assertEquals(deliveryId, ack2.getDeliveryId());
+
}
@@ -857,18 +860,18 @@
int objectId = 54321;
- List ids = new ArrayList();
+ List cancels = new ArrayList();
- AckInfo ack1 = new AckInfo(1254, 78123, 22);
- AckInfo ack2 = new AckInfo(786, 8979, 461);
- ids.add(ack1);
- ids.add(ack2);
+ Cancel cancel1 = new Cancel(65654, 43);
+ Cancel cancel2 = new Cancel(65765, 2);
+ cancels.add(cancel1);
+ cancels.add(cancel2);
MethodInvocation mi = new MethodInvocation(null, methodHash, cancelDeliveriesMethod, cancelDeliveriesMethod, null);
mi.getMetaData().addMetaData(Dispatcher.DISPATCHER, Dispatcher.OID, new Integer(objectId));
- mi.setArguments(new Object[] {ids});
+ mi.setArguments(new Object[] {cancels});
MessagingMarshallable mm = new MessagingMarshallable((byte)77, mi);
@@ -909,27 +912,22 @@
assertEquals(2, size);
//then the AckInfos
- AckInfo rack1 = new AckInfo();
+ Cancel rcancel1 = new Cancel();
- AckInfo rack2 = new AckInfo();
+ Cancel rcancel2 = new Cancel();
- rack1.read(dis);
+ rcancel1.read(dis);
- rack2.read(dis);
+ rcancel2.read(dis);
- assertEquals(ack1.getConsumerID(), rack1.getConsumerID());
+ assertEquals(cancel1.getDeliveryCount(), rcancel1.getDeliveryCount());
- assertEquals(ack1.getMessageID(), rack1.getMessageID());
+ assertEquals(cancel1.getDeliveryId(), cancel1.getDeliveryId());
- assertEquals(ack1.getDeliveryCount(), rack1.getDeliveryCount());
+ assertEquals(cancel2.getDeliveryCount(), rcancel2.getDeliveryCount());
- assertEquals(ack2.getConsumerID(), rack2.getConsumerID());
-
- assertEquals(ack2.getMessageID(), rack2.getMessageID());
-
- assertEquals(ack2.getDeliveryCount(), rack2.getDeliveryCount());
-
-
+ assertEquals(cancel2.getDeliveryId(), cancel2.getDeliveryId());
+
//should be eos
try
@@ -963,16 +961,17 @@
assertEquals(2, list.size());
- AckInfo xack1 = (AckInfo)list.get(0);
- AckInfo xack2 = (AckInfo)list.get(1);
+ Cancel xack1 = (Cancel)list.get(0);
+ Cancel xack2 = (Cancel)list.get(1);
- assertEquals(ack1.getConsumerID(), xack1.getConsumerID());
+ assertEquals(cancel1.getDeliveryId(), xack1.getDeliveryId());
- assertEquals(ack1.getMessageID(), xack1.getMessageID());
+ assertEquals(cancel1.getDeliveryCount(), xack1.getDeliveryCount());
- assertEquals(ack2.getConsumerID(), xack2.getConsumerID());
+ assertEquals(cancel2.getDeliveryId(), xack2.getDeliveryId());
- assertEquals(ack2.getMessageID(), xack2.getMessageID());
+ assertEquals(cancel2.getDeliveryCount(), xack2.getDeliveryCount());
+
}
public void testNullResponse() throws Exception
@@ -1100,17 +1099,15 @@
{
int consumerID = 12345678;
- int serverId = 76543;
-
JBossMessage m1 = new JBossMessage(123);
JBossMessage m2 = new JBossMessage(456);
JBossMessage m3 = new JBossMessage(789);
List msgs = new ArrayList();
- MessageProxy del1 = JBossMessage.createThinDelegate(m1, 7);
- MessageProxy del2 = JBossMessage.createThinDelegate(m2, 8);
- MessageProxy del3 = JBossMessage.createThinDelegate(m3, 9);
+ MessageProxy del1 = JBossMessage.createThinDelegate(1, m1, 7);
+ MessageProxy del2 = JBossMessage.createThinDelegate(2, m2, 8);
+ MessageProxy del3 = JBossMessage.createThinDelegate(3, m3, 9);
MessageTest.configureMessage(m1);
MessageTest.configureMessage(m2);
@@ -1120,7 +1117,7 @@
msgs.add(del2);
msgs.add(del3);
- ClientDelivery dr = new ClientDelivery(msgs, serverId, consumerID);
+ ClientDelivery dr = new ClientDelivery(msgs, consumerID);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -1149,23 +1146,21 @@
//Next should be sessionID
assertEquals("dummySessionId", dis.readUTF());
- //Next int should be server id
- assertEquals(76543, dis.readInt());
-
//Next int should be consumer id
assertEquals(12345678, dis.readInt());
//Next int should be number of messages
assertEquals(3, dis.readInt());
-
-
-
+
//Next byte should be type
assertEquals(JBossMessage.TYPE, dis.readByte());
//Next int should be delivery count
assertEquals(7, dis.readInt());
+ //Delivery id
+ assertEquals(1, dis.readLong());
+
//And now the message itself
JBossMessage r1 = new JBossMessage();
@@ -1178,6 +1173,9 @@
//Next int should be delivery count
assertEquals(8, dis.readInt());
+ // Delivery id
+ assertEquals(2, dis.readLong());
+
//And now the message itself
JBossMessage r2 = new JBossMessage();
@@ -1190,6 +1188,9 @@
//Next int should be delivery count
assertEquals(9, dis.readInt());
+ // Delivery id
+ assertEquals(3, dis.readLong());
+
//And now the message itself
JBossMessage r3 = new JBossMessage();
@@ -1232,7 +1233,6 @@
List msgs2 = dr2.getMessages();
- assertEquals(serverId, dr2.getServerId());
assertEquals(consumerID, dr2.getConsumerId());
MessageProxy p1 = (MessageProxy)msgs2.get(0);
Modified: trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -113,15 +113,15 @@
try
{
- conn1 = factory.createConnection();
+ conn1 = factory.createConnection(); //server 0
- conn2 = factory.createConnection();
+ conn2 = factory.createConnection(); //server 1
- conn3 = factory.createConnection();
+ conn3 = factory.createConnection(); //server 2
- conn4 = factory.createConnection();
+ conn4 = factory.createConnection(); //server 0
- conn5 = factory.createConnection();
+ conn5 = factory.createConnection(); //server 1
ConnectionState state1 = (ConnectionState)(((DelegateSupport)((JBossConnection)conn1).getDelegate()).getState());
@@ -441,6 +441,8 @@
int server1Id = cf2.getServerID();
int server2Id = cf3.getServerID();
+
+ //Server order should be 2, 0, 1
log.info("server 0 id: " + server0Id);
@@ -462,15 +464,19 @@
Connection conn = null;
+ boolean killed = false;
+
try
- {
-
- //Get a connection on server 1
+ {
+ conn = factory.createConnection(); //connection on server 2
+
+ conn.close();
+
conn = factory.createConnection(); //connection on server 0
conn.close();
- conn = factory.createConnection(); //connection on server 1
+ conn = factory.createConnection(); // connection on server 1
JBossConnection jbc = (JBossConnection)conn;
@@ -505,6 +511,8 @@
ServerManagement.kill(1);
+ killed = true;
+
log.info("killed server, now waiting");
Thread.sleep(5000);
@@ -546,8 +554,14 @@
catch (Exception e)
{
e.printStackTrace();
- }
+ }
}
+
+ //Resurrect dead server
+ if (killed)
+ {
+ ServerManagement.spawn(1);
+ }
}
}
@@ -597,14 +611,15 @@
Connection conn = null;
+ boolean killed = false;
+
try
{
- //Get a connection on server 1
- conn = factory.createConnection(); //connection on server 0
+ conn = factory.createConnection(); //connection on server 1
conn.close();
- conn = factory.createConnection(); //connection on server 1
+ conn = factory.createConnection(); //connection on server 2
JBossConnection jbc = (JBossConnection)conn;
@@ -614,7 +629,7 @@
int initialServerID = state.getServerID();
- assertEquals(1, initialServerID);
+ assertEquals(2, initialServerID);
Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -653,9 +668,11 @@
ServerManagement.kill(1);
+ killed = true;
+
log.info("killed server, now waiting");
- Thread.sleep(5000);
+ Thread.sleep(10000);
log.info("done wait");
@@ -720,6 +737,12 @@
e.printStackTrace();
}
}
+
+ // Resurrect dead server
+ if (killed)
+ {
+ ServerManagement.spawn(1);
+ }
}
}
@@ -768,6 +791,8 @@
Connection conn = null;
+ boolean killed = false;
+
try
{
//Get a connection on server 1
@@ -825,6 +850,8 @@
log.info("************ KILLING (CRASHING) SERVER 1");
ServerManagement.kill(1);
+
+ killed = true;
log.info("killed server, now waiting");
@@ -893,51 +920,16 @@
e.printStackTrace();
}
}
+
+ if (killed)
+ {
+ ServerManagement.spawn(1);
+ }
}
}
-
-
-// public void testEvenSimplerFailover() throws Exception
-// {
-// JBossConnectionFactory factory = (JBossConnectionFactory )ic[0].lookup("/ConnectionFactory");
-//
-// Connection conn = null;
-//
-// try
-// {
-// conn = factory.createConnection();
-//
-// log.info("************ KILLING (CRASHING) SERVER 0");
-//
-// ServerManagement.getServer(0).destroy();
-//
-// log.info("killed server, now waiting");
-//
-// Thread.sleep(25000);
-//
-// log.info("done wait");
-// }
-// finally
-// {
-// if (conn != null)
-// {
-// try
-// {
-// conn.close();
-// }
-// catch (Exception e)
-// {
-// e.printStackTrace();
-// }
-// }
-// }
-//
-// }
-
-
// public void testConnectionFactoryConnect() throws Exception
// {
// try
Modified: trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -11,6 +11,8 @@
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.jboss.jms.util.XMLUtil;
+import org.jboss.logging.Logger;
+import org.jboss.test.messaging.tools.jmx.rmi.LocalTestServer;
import javax.management.ObjectName;
import java.util.Map;
@@ -30,7 +32,10 @@
public class MBeanConfigurationElement
{
// Constants -----------------------------------------------------
+
+ private static final Logger log = Logger.getLogger(MBeanConfigurationElement.class);
+
// Static --------------------------------------------------------
public static Class stringToClass(String type) throws Exception
@@ -82,6 +87,8 @@
Node mbeanNameAttr = attrs.getNamedItem("name");
on = new ObjectName(mbeanNameAttr.getNodeValue());
+
+ log.trace("ObjectName is: " + on);
Node mbeanCodeAttr = attrs.getNamedItem("code");
className = mbeanCodeAttr.getNodeValue();
Modified: trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java 2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java 2006-12-14 19:32:42 UTC (rev 1794)
@@ -728,6 +728,8 @@
int defaultTempQueuePageSize,
int defaultTempQueueDownCacheSize) throws Exception
{
+ log.trace("deploying connection factory with name: " + objectName);
+
String config =
"<mbean code=\"org.jboss.jms.server.connectionfactory.ConnectionFactory\"\n" +
"name=\"" + objectName + "\"\n" +
@@ -766,6 +768,9 @@
MBeanConfigurationElement mc = new MBeanConfigurationElement(XMLUtil.stringToElement(config));
ObjectName on = sc.registerAndConfigureService(mc);
+
+ log.trace("Object name is now: " + on);
+
sc.invoke(on, "create", new Object[0], new String[0]);
sc.invoke(on, "start", new Object[0], new String[0]);
}
More information about the jboss-cvs-commits
mailing list