/*
* 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.test.messaging.jms;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.StreamMessage;
import javax.jms.TextMessage;
import javax.jms.TopicConnection;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.management.ObjectName;
import org.jboss.jms.client.JBossSession;
import org.jboss.jms.client.delegate.ClientSessionDelegate;
import org.jboss.jms.client.delegate.DelegateSupport;
import org.jboss.jms.client.state.SessionState;
import org.jboss.test.messaging.tools.ServerManagement;
import EDU.oswego.cs.dl.util.concurrent.Latch;
/**
* @author <a href="mailto:tim.fox@jboss.com">Tim Fox</a>
*
* $Id: AcknowledgementTest.java 8449 2011-10-19 03:17:35Z gaohoward $
*/
public class AcknowledgementTest extends JMSTestCase
{
// Constants -----------------------------------------------------
// Static --------------------------------------------------------
// Attributes ----------------------------------------------------
// Constructors --------------------------------------------------
public AcknowledgementTest(String name)
{
super(name);
}
// TestCase overrides -------------------------------------------
// Public --------------------------------------------------------
public void testMemLeakInDifferentAckModes() throws Exception
{
final int NUM_MSG = 50;
Connection conn = null;
Session producerSess = null;
Session consumerSess = null;
//auto
log.info("Testing leak in AUTO_ACKNOWLEDGE mode...");
try
{
conn = cf.createConnection();
producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
consumerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
//Send some messages
for (int i = 0; i < NUM_MSG; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
log.trace("Sent messages");
int count = 0;
Message m = null;
for (int i = 0; i < NUM_MSG; i++)
{
m = consumer.receive(2000);
if (m == null) break;
count++;
}
assertRemainingMessages(0);
assertEquals(count, NUM_MSG);
checkSessionAckMap((JBossSession)consumerSess);
}
finally
{
if (conn != null)
{
conn.close();
}
conn = null;
producerSess = null;
consumerSess = null;
}
//dups
log.info("Testing leak in DUPS_OK_ACKNOWLEDGE mode...");
final int BATCH_SIZE = 10;
String mbeanConfig =
"<mbean code=\"org.jboss.jms.server.connectionfactory.ConnectionFactory\"\n" +
" name=\"jboss.messaging.destination:service=DupsConnectionFactory\"\n" +
" xmbean-dd=\"xmdesc/ConnectionFactory-xmbean.xml\">\n" +
" <depends optional-attribute-name=\"ServerPeer\">jboss.messaging:service=ServerPeer</depends>\n" +
" <depends optional-attribute-name=\"Connector\">jboss.messaging:service=Connector,transport=bisocket</depends>\n" +
" <attribute name=\"JNDIBindings\">\n" +
" <bindings>\n" +
" <binding>/mycf</binding>\n" +
" </bindings>\n" +
" </attribute>\n" +
" <attribute name=\"DupsOKBatchSize\">" + BATCH_SIZE + "</attribute>" +
" </mbean>";
ObjectName on = ServerManagement.deploy(mbeanConfig);
ServerManagement.invoke(on, "create", new Object[0], new String[0]);
ServerManagement.invoke(on, "start", new Object[0], new String[0]);
try
{
ConnectionFactory myCF = (ConnectionFactory)ic.lookup("/mycf");
conn = myCF.createConnection();
producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
consumerSess = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
//Send some messages
for (int i = 0; i < NUM_MSG; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
log.trace("Sent messages");
Message m = null;
for (int i = 0; i < NUM_MSG; i++)
{
m = consumer.receive(2000);
assertNotNull(m);
}
checkSessionAckMap((JBossSession)consumerSess);
}
finally
{
if (conn != null)
{
conn.close();
}
conn = null;
producerSess = null;
consumerSess = null;
ServerManagement.invoke(on, "stop", new Object[0], new String[0]);
ServerManagement.invoke(on, "destroy", new Object[0], new String[0]);
}
//client
log.info("Testing leak in CLIENT_ACKNOWLEDGE mode...");
try
{
conn = cf.createConnection();
producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
//Send some messages
for (int i = 0; i < NUM_MSG; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
log.trace("Sent messages");
Message m = null;
for (int i = 0; i < NUM_MSG; i++)
{
m = consumer.receive(2000);
}
m.acknowledge();
assertRemainingMessages(0);
checkSessionAckMap((JBossSession)consumerSess);
}
finally
{
if (conn != null)
{
conn.close();
}
conn = null;
producerSess = null;
consumerSess = null;
}
//transactional (actually the ackMap is not used in tx mode (including XA), but test anyway)
log.info("Testing leak in SESSION_TRANSACTED mode...");
try
{
conn = cf.createConnection();
producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
//Send some messages
for (int i = 0; i < NUM_MSG; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
log.trace("Sent messages");
Message m = null;
for (int i = 0; i < NUM_MSG; i++)
{
m = consumer.receive(2000);
}
consumerSess.commit();
assertRemainingMessages(0);
checkSessionAckMap((JBossSession)consumerSess);
}
finally
{
if (conn != null)
{
conn.close();
}
conn = null;
producerSess = null;
consumerSess = null;
}
//recover
log.info("Testing leak in CLIENT_ACKNOWLEDGE mode with recover ...");
try
{
conn = cf.createConnection();
producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
//Send some messages
for (int i = 0; i < NUM_MSG; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
log.trace("Sent messages");
Message m = null;
for (int i = 0; i < NUM_MSG; i++)
{
m = consumer.receive(2000);
}
consumerSess.recover();
for (int i = 0; i < NUM_MSG; i++)
{
m = consumer.receive(2000);
}
m.acknowledge();
assertRemainingMessages(0);
checkSessionAckMap((JBossSession)consumerSess);
}
finally
{
if (conn != null)
{
conn.close();
}
conn = null;
producerSess = null;
consumerSess = null;
}
}
/**
* make sure the session's ackMap is cleared.
*/
private void checkSessionAckMap(JBossSession session)
{
DelegateSupport support = (DelegateSupport)session.getDelegate();
SessionState state = (SessionState)support.getState();
assertEquals(0, state.getAckMap().size());
}
/* Topics shouldn't hold on to messages if there are no subscribers */
public void testPersistentMessagesForTopicDropped() throws Exception
{
TopicConnection conn = null;
try
{
conn = cf.createTopicConnection();
TopicSession sess = conn.createTopicSession(true, 0);
TopicPublisher pub = sess.createPublisher(topic1);
pub.setDeliveryMode(DeliveryMode.PERSISTENT);
Message m = sess.createTextMessage("testing123");
pub.publish(m);
sess.commit();
conn.close();
checkEmpty(topic1);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
/* Topics shouldn't hold on to messages when the non-durable subscribers close */
public void testPersistentMessagesForTopicDropped2() throws Exception
{
TopicConnection conn = null;
try
{
conn = cf.createTopicConnection();
conn.start();
TopicSession sess = conn.createTopicSession(true, 0);
TopicPublisher pub = sess.createPublisher(topic1);
TopicSubscriber sub = sess.createSubscriber(topic1);
pub.setDeliveryMode(DeliveryMode.PERSISTENT);
Message m = sess.createTextMessage("testing123");
pub.publish(m);
sess.commit();
//receive but rollback
TextMessage m2 = (TextMessage)sub.receive(3000);
assertNotNull(m2);
assertEquals("testing123", m2.getText());
sess.rollback();
conn.close();
checkEmpty(topic1);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testRollbackRecover() throws Exception
{
TopicConnection conn = null;
try
{
conn = cf.createTopicConnection();
TopicSession sess = conn.createTopicSession(true, 0);
TopicPublisher pub = sess.createPublisher(topic1);
TopicSubscriber cons = sess.createSubscriber(topic1);
conn.start();
Message m = sess.createTextMessage("testing123");
pub.publish(m);
sess.commit();
TextMessage m2 = (TextMessage)cons.receive(3000);
assertNotNull(m2);
assertEquals("testing123", m2.getText());
sess.rollback();
m2 = (TextMessage)cons.receive(3000);
assertNotNull(m2);
assertEquals("testing123", m2.getText());
conn.close();
conn = cf.createTopicConnection();
conn.start();
//test 2
TopicSession newsess = conn.createTopicSession(true, 0);
TopicPublisher newpub = newsess.createPublisher(topic1);
TopicSubscriber newcons = newsess.createSubscriber(topic1);
Message m3 = newsess.createTextMessage("testing456");
newpub.publish(m3);
newsess.commit();
TextMessage m4 = (TextMessage)newcons.receive(3000);
assertNotNull(m4);
assertEquals("testing456", m4.getText());
newsess.commit();
newpub.publish(m3);
newsess.commit();
TextMessage m5 = (TextMessage)newcons.receive(3000);
assertNotNull(m5);
assertEquals("testing456", m5.getText());
newsess.rollback();
TextMessage m6 = (TextMessage)newcons.receive(3000);
assertNotNull(m6);
assertEquals("testing456", m6.getText());
newsess.commit();
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testTransactionalAcknowledgement() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(0);
producerSess.rollback();
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(0);
producerSess.commit();
assertRemainingMessages(NUM_MESSAGES);
log.trace("Sent messages");
int count = 0;
while (true)
{
Message m = consumer.receive(200);
if (m == null) break;
count++;
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Received " + count + " messages");
assertEquals(count, NUM_MESSAGES);
consumerSess.rollback();
assertRemainingMessages(NUM_MESSAGES);
log.trace("Session rollback called");
int i = 0;
for(; i < NUM_MESSAGES; i++)
{
consumer.receive();
log.trace("Received message " + i);
}
assertRemainingMessages(NUM_MESSAGES);
// if I don't receive enough messages, the test will timeout
log.trace("Received " + i + " messages after recover");
consumerSess.commit();
assertRemainingMessages(0);
checkEmpty(queue1);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
/**
* Send some messages, don't acknowledge them and verify that they are re-sent on recovery.
*/
public void testClientAcknowledgeNoAcknowledgement() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Sent messages");
int count = 0;
while (true)
{
Message m = consumer.receive(200);
if (m == null) break;
count++;
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Received " + count + " messages");
assertEquals(count, NUM_MESSAGES);
consumerSess.recover();
assertRemainingMessages(NUM_MESSAGES);
log.trace("Session recover called");
Message m = null;
int i = 0;
for(; i < NUM_MESSAGES; i++)
{
m = consumer.receive();
log.trace("Received message " + i);
}
assertRemainingMessages(NUM_MESSAGES);
// if I don't receive enough messages, the test will timeout
log.trace("Received " + i + " messages after recover");
m.acknowledge();
assertRemainingMessages(0);
// make sure I don't receive anything else
checkEmpty(queue1);
conn.close();
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
//JBMESSAGING-1886
public void testMessageBodyClearedBeforeRecover() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 10;
//1 Send some text messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
TextMessage m = producerSess.createTextMessage("text-message-to-recover");
producer.send(m);
}
log.trace("Sent text messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
TextMessage m = (TextMessage)consumer.receive(2000);
m.clearBody();
}
consumerSess.recover();
log.trace("Session recover called");
TextMessage tm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
tm = (TextMessage)consumer.receive();
assertEquals("text-message-to-recover", tm.getText());
}
tm.acknowledge();
//2 Send some byte messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
BytesMessage m = producerSess.createBytesMessage();
m.writeBytes(new byte[] {1, 2, 3});
producer.send(m);
}
log.trace("Sent byte messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
BytesMessage m = (BytesMessage)consumer.receive(2000);
m.clearBody();
}
consumerSess.recover();
log.trace("Session recover called");
BytesMessage bm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
byte[] buffer = new byte[3];
bm = (BytesMessage)consumer.receive();
assertEquals(3, bm.getBodyLength());
bm.readBytes(buffer);
//make sure the buffer is {1,2,3}
assertEquals(1, buffer[0]);
assertEquals(2, buffer[1]);
assertEquals(3, buffer[2]);
}
bm.acknowledge();
//3 Send some Map messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
MapMessage m = producerSess.createMapMessage();
m.setString("map-message", "hello-world");
producer.send(m);
}
log.trace("Sent map messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
MapMessage m = (MapMessage)consumer.receive(2000);
m.clearBody();
}
consumerSess.recover();
log.trace("Session recover called");
MapMessage mm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
mm = (MapMessage)consumer.receive();
String value = mm.getString("map-message");
assertEquals("hello-world", value);
}
mm.acknowledge();
//4 Send some Object messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
ObjectMessage m = producerSess.createObjectMessage(new String("object-message"));
producer.send(m);
}
log.trace("Sent object messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
ObjectMessage m = (ObjectMessage)consumer.receive(2000);
m.clearBody();
}
consumerSess.recover();
log.trace("Session recover called");
ObjectMessage om = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
om = (ObjectMessage)consumer.receive();
String value = (String)om.getObject();
assertEquals("object-message", value);
}
om.acknowledge();
//5 Send some Stream messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
StreamMessage m = producerSess.createStreamMessage();
m.writeString("stream-message");
producer.send(m);
}
log.trace("Sent stream messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
StreamMessage m = (StreamMessage)consumer.receive(2000);
String v = m.readString();
assertEquals("stream-message", v);
m.clearBody();
}
consumerSess.recover();
log.trace("Session recover called");
StreamMessage sm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
sm = (StreamMessage)consumer.receive();
String value = sm.readString();
assertEquals("stream-message", value);
}
sm.acknowledge();
checkEmpty(queue1);
conn.close();
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
//JBMESSAGING-1886
public void testMessagePropertiesClearedBeforeRecover() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 10;
//1 Send some text messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
TextMessage m = producerSess.createTextMessage("text-message-to-recover");
m.setBooleanProperty("text_message", true);
producer.send(m);
}
log.trace("Sent text messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
TextMessage m = (TextMessage)consumer.receive(2000);
Boolean value = m.getBooleanProperty("text_message");
assertTrue(value);
m.clearProperties();
value = m.getBooleanProperty("text_message");
//equals Boolean.valueOf((String)null);
assertFalse(value);
}
consumerSess.recover();
log.trace("Session recover called");
TextMessage tm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
tm = (TextMessage)consumer.receive();
Boolean value = tm.getBooleanProperty("text_message");
assertTrue(value);
}
tm.acknowledge();
//2 Send some byte messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
BytesMessage m = producerSess.createBytesMessage();
m.writeBytes(new byte[] {1, 2, 3});
m.setByteProperty("byte_property", (byte)3);
producer.send(m);
}
log.trace("Sent byte messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
BytesMessage m = (BytesMessage)consumer.receive(2000);
m.clearProperties();
}
consumerSess.recover();
log.trace("Session recover called");
BytesMessage bm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
byte[] buffer = new byte[3];
bm = (BytesMessage)consumer.receive();
byte prop = bm.getByteProperty("byte_property");
assertEquals(3, prop);
assertEquals(3, bm.getBodyLength());
bm.readBytes(buffer);
//make sure the buffer is {1,2,3}
assertEquals(1, buffer[0]);
assertEquals(2, buffer[1]);
assertEquals(3, buffer[2]);
}
bm.acknowledge();
//3 Send some Map messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
MapMessage m = producerSess.createMapMessage();
m.setString("map-message", "hello-world");
m.setDoubleProperty("double_property", new Double(25));
producer.send(m);
}
log.trace("Sent map messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
MapMessage m = (MapMessage)consumer.receive(2000);
//this time clear both.
m.clearBody();
m.clearProperties();
}
consumerSess.recover();
log.trace("Session recover called");
MapMessage mm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
mm = (MapMessage)consumer.receive();
String value = mm.getString("map-message");
assertEquals("hello-world", value);
Double db = mm.getDoubleProperty("double_property");
assertEquals(new Double(25), db);
}
mm.acknowledge();
//4 Send some Object messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
ObjectMessage m = producerSess.createObjectMessage(new String("object-message"));
m.setObjectProperty("object_property", new String("abcdef"));
producer.send(m);
}
log.trace("Sent object messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
ObjectMessage m = (ObjectMessage)consumer.receive(2000);
m.clearProperties();
}
consumerSess.recover();
log.trace("Session recover called");
ObjectMessage om = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
om = (ObjectMessage)consumer.receive();
String value = (String)om.getObject();
assertEquals("object-message", value);
String prop = (String)om.getObjectProperty("object_property");
assertEquals("abcdef", prop);
}
om.acknowledge();
//5 Send some Stream messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
StreamMessage m = producerSess.createStreamMessage();
m.writeString("stream-message");
m.setFloatProperty("float_property", 1.05f);
m.setIntProperty("int_property", 100);
producer.send(m);
}
log.trace("Sent stream messages");
for (int i = 0; i < NUM_MESSAGES; i++)
{
StreamMessage m = (StreamMessage)consumer.receive(2000);
String v = m.readString();
assertEquals("stream-message", v);
m.clearProperties();
}
consumerSess.recover();
log.trace("Session recover called");
StreamMessage sm = null;
for(int i = 0; i < NUM_MESSAGES; i++)
{
sm = (StreamMessage)consumer.receive();
String value = sm.readString();
assertEquals("stream-message", value);
float prop = sm.getFloatProperty("float_property");
int prop2 = sm.getIntProperty("int_property");
assertEquals(1.05f, prop);
assertEquals(100, prop2);
}
sm.acknowledge();
checkEmpty(queue1);
conn.close();
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
/**
* Send some messages, acknowledge them individually and verify they are not resent after
* recovery.
*/
public void testIndividualClientAcknowledge() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(NUM_MESSAGES);
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = consumer.receive(200);
assertNotNull(m);
assertRemainingMessages(NUM_MESSAGES - i);
m.acknowledge();
assertRemainingMessages(NUM_MESSAGES - (i + 1));
}
assertRemainingMessages(0);
consumerSess.recover();
Message m = consumer.receive(200);
assertNull(m);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
/**
* Send some messages, acknowledge them once after all have been received verify they are not
* resent after recovery
*/
public void testBulkClientAcknowledge() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Sent messages");
Message m = null;
int count = 0;
for (int i = 0; i < NUM_MESSAGES; i++)
{
m = consumer.receive(200);
if (m == null) break;
count++;
}
assertRemainingMessages(NUM_MESSAGES);
assertNotNull(m);
m.acknowledge();
assertRemainingMessages(0);
log.trace("Received " + count + " messages");
assertEquals(count, NUM_MESSAGES);
consumerSess.recover();
log.trace("Session recover called");
m = consumer.receive(200);
log.trace("Message is:" + m);
assertNull(m);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
/**
* Send some messages, acknowledge some of them, and verify that the others are resent after
* delivery
*/
public void testPartialClientAcknowledge() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
final int ACKED_MESSAGES = 11;
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Sent messages");
int count = 0;
Message m = null;
for (int i = 0; i < NUM_MESSAGES; i++)
{
m = consumer.receive(200);
if (m == null)
{
break;
}
if (count == ACKED_MESSAGES -1)
{
m.acknowledge();
}
count++;
}
assertRemainingMessages(NUM_MESSAGES - ACKED_MESSAGES);
assertNotNull(m);
log.trace("Received " + count + " messages");
assertEquals(count, NUM_MESSAGES);
consumerSess.recover();
log.trace("Session recover called");
count = 0;
while (true)
{
m = consumer.receive(200);
if (m == null) break;
count++;
}
assertEquals(NUM_MESSAGES - ACKED_MESSAGES, count);
}
finally
{
if (conn != null)
{
conn.close();
}
removeAllMessages(queue1.getQueueName(), true, 0);
}
}
/*
* Send some messages, consume them and verify the messages are not sent upon recovery
*
*/
public void testAutoAcknowledge() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Sent messages");
int count = 0;
Message m = null;
for (int i = 0; i < NUM_MESSAGES; i++)
{
assertRemainingMessages(NUM_MESSAGES - i);
m = consumer.receive(2000);
assertRemainingMessages(NUM_MESSAGES - (i + 1));
if (m == null) break;
count++;
}
assertRemainingMessages(0);
assertNotNull(m);
log.trace("Received " + count + " messages");
assertEquals(count, NUM_MESSAGES);
consumerSess.recover();
log.trace("Session recover called");
m = consumer.receive(2000);
log.trace("Message is:" + m);
assertNull(m);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testDupsOKBatchDefault() throws Exception
{
//test default
Connection conn = null;
try
{
conn = cf.createConnection();
JBossSession sess = (JBossSession)conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
ClientSessionDelegate del = (ClientSessionDelegate)sess.getDelegate();
assertEquals(1000, del.getDupsOKBatchSize());
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testDupsOKAcknowledgeQueue() throws Exception
{
final int BATCH_SIZE = 10;
String mbeanConfig =
"<mbean code=\"org.jboss.jms.server.connectionfactory.ConnectionFactory\"\n" +
" name=\"jboss.messaging.destination:service=MyConnectionFactory\"\n" +
" xmbean-dd=\"xmdesc/ConnectionFactory-xmbean.xml\">\n" +
" <depends optional-attribute-name=\"ServerPeer\">jboss.messaging:service=ServerPeer</depends>\n" +
" <depends optional-attribute-name=\"Connector\">jboss.messaging:service=Connector,transport=bisocket</depends>\n" +
" <attribute name=\"JNDIBindings\">\n" +
" <bindings>\n" +
" <binding>/mycf</binding>\n" +
" </bindings>\n" +
" </attribute>\n" +
" <attribute name=\"DupsOKBatchSize\">" + BATCH_SIZE + "</attribute>" +
" </mbean>";
ObjectName on = ServerManagement.deploy(mbeanConfig);
ServerManagement.invoke(on, "create", new Object[0], new String[0]);
ServerManagement.invoke(on, "start", new Object[0], new String[0]);
Connection conn = null;
try
{
ConnectionFactory myCF = (ConnectionFactory)ic.lookup("/mycf");
conn = myCF.createConnection();
Session producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
//Send some messages
for (int i = 0; i < 19; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(19);
log.trace("Sent messages");
Message m = null;
for (int i = 0; i < 10; i++)
{
m = consumer.receive(2000);
assertNotNull(m);
if (i == 9)
{
assertRemainingMessages(9);
}
else
{
assertRemainingMessages(19);
}
}
for (int i = 0; i < 9; i++)
{
m = consumer.receive(2000);
assertNotNull(m);
assertRemainingMessages(9);
}
//Make sure the last are acked on close
consumerSess.close();
assertRemainingMessages(0);
}
finally
{
if (conn != null)
{
conn.close();
}
ServerManagement.invoke(on, "stop", new Object[0], new String[0]);
ServerManagement.invoke(on, "destroy", new Object[0], new String[0]);
}
}
public void testDupsOKAcknowledgeTopic() throws Exception
{
final int BATCH_SIZE = 10;
String mbeanConfig =
"<mbean code=\"org.jboss.jms.server.connectionfactory.ConnectionFactory\"\n" +
" name=\"jboss.messaging.destination:service=MyConnectionFactory2\"\n" +
" xmbean-dd=\"xmdesc/ConnectionFactory-xmbean.xml\">\n" +
" <depends optional-attribute-name=\"ServerPeer\">jboss.messaging:service=ServerPeer</depends>\n" +
" <depends optional-attribute-name=\"Connector\">jboss.messaging:service=Connector,transport=bisocket</depends>\n" +
" <attribute name=\"JNDIBindings\">\n" +
" <bindings>\n" +
" <binding>/mycf</binding>\n" +
" </bindings>\n" +
" </attribute>\n" +
" <attribute name=\"DupsOKBatchSize\">" + BATCH_SIZE + "</attribute>" +
" </mbean>";
ObjectName on = ServerManagement.deploy(mbeanConfig);
ServerManagement.invoke(on, "create", new Object[0], new String[0]);
ServerManagement.invoke(on, "start", new Object[0], new String[0]);
Connection conn = null;
try
{
ConnectionFactory myCF = (ConnectionFactory)ic.lookup("/mycf");
conn = myCF.createConnection();
Session producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(topic1);
Session consumerSess = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(topic1);
conn.start();
//Send some messages
for (int i = 0; i < 19; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
log.trace("Sent messages");
Message m = null;
for (int i = 0; i < 19; i++)
{
m = consumer.receive(200);
assertNotNull(m);
}
consumerSess.close();
}
finally
{
if (conn != null)
{
conn.close();
}
ServerManagement.invoke(on, "stop", new Object[0], new String[0]);
ServerManagement.invoke(on, "destroy", new Object[0], new String[0]);
}
}
/*
* Send some messages, consume them and verify the messages are not sent upon recovery
*
*/
public void testLazyAcknowledge() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session producerSess = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
MessageProducer producer = producerSess.createProducer(queue1);
Session consumerSess = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
MessageConsumer consumer = consumerSess.createConsumer(queue1);
conn.start();
final int NUM_MESSAGES = 20;
//Send some messages
for (int i = 0; i < NUM_MESSAGES; i++)
{
Message m = producerSess.createMessage();
producer.send(m);
}
assertRemainingMessages(NUM_MESSAGES);
log.trace("Sent messages");
int count = 0;
Message m = null;
for (int i = 0; i < NUM_MESSAGES; i++)
{
m = consumer.receive(200);
if (m == null) break;
count++;
}
assertNotNull(m);
assertRemainingMessages(NUM_MESSAGES);
log.trace("Received " + count + " messages");
assertEquals(count, NUM_MESSAGES);
consumerSess.recover();
log.trace("Session recover called");
m = consumer.receive(200);
log.trace("Message is:" + m);
assertNull(m);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testMessageListenerAutoAck() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sessSend.createProducer(queue1);
log.trace("Sending messages");
TextMessage tm1 = sessSend.createTextMessage("a");
TextMessage tm2 = sessSend.createTextMessage("b");
TextMessage tm3 = sessSend.createTextMessage("c");
prod.send(tm1);
prod.send(tm2);
prod.send(tm3);
log.trace("Sent messages");
sessSend.close();
assertRemainingMessages(3);
conn.start();
Session sessReceive = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
log.trace("Creating consumer");
MessageConsumer cons = sessReceive.createConsumer(queue1);
log.trace("Created consumer");
MessageListenerAutoAck listener = new MessageListenerAutoAck(sessReceive);
log.trace("Setting message listener");
cons.setMessageListener(listener);
log.trace("Set message listener");
listener.waitForMessages();
Thread.sleep(500);
assertRemainingMessages(0);
assertFalse(listener.failed);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
/*
* This test will:
* - Send two messages over a producer
* - Receive one message over a consumer
* - Call Recover
* - Receive the second message
* - The queue should be empty after that
* Note: testMessageListenerAutoAck will test a similar case using MessageListeners
*/
public void testRecoverAutoACK() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer p = s.createProducer(queue1);
p.setDeliveryMode(DeliveryMode.PERSISTENT);
Message m = s.createTextMessage("one");
p.send(m);
m = s.createTextMessage("two");
p.send(m);
conn.close();
conn = null;
assertRemainingMessages(2);
conn = cf.createConnection();
conn.start();
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = session.createConsumer(queue1);
TextMessage messageReceived = (TextMessage)consumer.receive(1000);
assertNotNull(messageReceived);
assertEquals("one", messageReceived.getText());
session.recover();
messageReceived = (TextMessage)consumer.receive(1000);
assertEquals("two", messageReceived.getText());
consumer.close();
// I can't call xasession.close for this test as JCA layer would cache the session
// So.. keep this close commented!
//xasession.close();
assertRemainingMessages(0);
}
finally
{
if (conn != null)
{
conn.close();
}
ServerManagement.undeployQueue("MyQueue2");
}
}
public void testMessageListenerDupsOK() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sessSend.createProducer(queue1);
log.trace("Sending messages");
TextMessage tm1 = sessSend.createTextMessage("a");
TextMessage tm2 = sessSend.createTextMessage("b");
TextMessage tm3 = sessSend.createTextMessage("c");
prod.send(tm1);
prod.send(tm2);
prod.send(tm3);
log.trace("Sent messages");
sessSend.close();
assertRemainingMessages(3);
conn.start();
Session sessReceive = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
log.trace("Creating consumer");
MessageConsumer cons = sessReceive.createConsumer(queue1);
log.trace("Created consumer");
MessageListenerDupsOK listener = new MessageListenerDupsOK(sessReceive);
log.trace("Setting message listener");
cons.setMessageListener(listener);
log.trace("Set message listener");
listener.waitForMessages();
assertRemainingMessages(3);
conn.close();
Thread.sleep(500);
assertRemainingMessages(0);
assertFalse(listener.failed);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testMessageListenerClientAck() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sessSend.createProducer(queue1);
TextMessage tm1 = sessSend.createTextMessage("a");
TextMessage tm2 = sessSend.createTextMessage("b");
TextMessage tm3 = sessSend.createTextMessage("c");
prod.send(tm1);
prod.send(tm2);
prod.send(tm3);
sessSend.close();
assertRemainingMessages(3);
conn.start();
Session sessReceive = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageConsumer cons = sessReceive.createConsumer(queue1);
MessageListenerClientAck listener = new MessageListenerClientAck(sessReceive);
cons.setMessageListener(listener);
listener.waitForMessages();
Thread.sleep(500);
assertRemainingMessages(0);
conn.close();
assertFalse(listener.failed);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
public void testMessageListenerTransactionalAck() throws Exception
{
Connection conn = null;
try
{
conn = cf.createConnection();
Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sessSend.createProducer(queue1);
TextMessage tm1 = sessSend.createTextMessage("a");
TextMessage tm2 = sessSend.createTextMessage("b");
TextMessage tm3 = sessSend.createTextMessage("c");
prod.send(tm1);
prod.send(tm2);
prod.send(tm3);
sessSend.close();
assertRemainingMessages(3);
conn.start();
Session sessReceive = conn.createSession(true, Session.SESSION_TRANSACTED);
MessageConsumer cons = sessReceive.createConsumer(queue1);
MessageListenerTransactionalAck listener = new MessageListenerTransactionalAck(sessReceive);
cons.setMessageListener(listener);
listener.waitForMessages();
Thread.sleep(500);
assertRemainingMessages(0);
conn.close();
assertFalse(listener.failed);
}
finally
{
if (conn != null)
{
conn.close();
}
}
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
private abstract class LatchListener implements MessageListener
{
protected Latch latch = new Latch();
protected Session sess;
protected int count = 0;
boolean failed;
LatchListener(Session sess)
{
this.sess = sess;
}
public void waitForMessages() throws InterruptedException
{
latch.acquire();
}
public abstract void onMessage(Message m);
}
private class MessageListenerAutoAck extends LatchListener
{
MessageListenerAutoAck(Session sess)
{
super(sess);
}
public void onMessage(Message m)
{
try
{
count++;
TextMessage tm = (TextMessage)m;
log.trace("Got message: " + tm.getText());
// Receive first three messages then recover() session
// Only last message should be redelivered
if (count == 1)
{
assertRemainingMessages(3);
if (!"a".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 2)
{
assertRemainingMessages(2);
if (!"b".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 3)
{
assertRemainingMessages(1);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
sess.recover();
}
if (count == 4)
{
assertRemainingMessages(1);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
latch.release();
}
}
catch (Exception e)
{
failed = true;
latch.release();
}
}
}
private class MessageListenerDupsOK extends LatchListener
{
MessageListenerDupsOK(Session sess)
{
super(sess);
}
public void onMessage(Message m)
{
try
{
count++;
TextMessage tm = (TextMessage)m;
// Receive first three messages then recover() session
// Only last message should be redelivered
if (count == 1)
{
assertRemainingMessages(3);
if (!"a".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 2)
{
assertRemainingMessages(3);
if (!"b".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 3)
{
assertRemainingMessages(3);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
sess.recover();
}
if (count == 4)
{
assertRemainingMessages(3);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
latch.release();
}
}
catch (Exception e)
{
failed = true;
latch.release();
}
}
}
private class MessageListenerClientAck extends LatchListener
{
MessageListenerClientAck(Session sess)
{
super(sess);
}
public void onMessage(Message m)
{
try
{
count++;
TextMessage tm = (TextMessage)m;
if (count == 1)
{
assertRemainingMessages(3);
if (!"a".equals(tm.getText()))
{
log.trace("Expected a but got " + tm.getText());
failed = true;
latch.release();
}
}
if (count == 2)
{
assertRemainingMessages(3);
if (!"b".equals(tm.getText()))
{
log.trace("Expected b but got " + tm.getText());
failed = true;
latch.release();
}
}
if (count == 3)
{
assertRemainingMessages(3);
if (!"c".equals(tm.getText()))
{
log.trace("Expected c but got " + tm.getText());
failed = true;
latch.release();
}
sess.recover();
}
if (count == 4)
{
assertRemainingMessages(3);
if (!"a".equals(tm.getText()))
{
log.trace("Expected a but got " + tm.getText());
failed = true;
latch.release();
}
tm.acknowledge();
assertRemainingMessages(2);
sess.recover();
}
if (count == 5)
{
assertRemainingMessages(2);
if (!"b".equals(tm.getText()))
{
log.trace("Expected b but got " + tm.getText());
failed = true;
latch.release();
}
sess.recover();
}
if (count == 6)
{
assertRemainingMessages(2);
if (!"b".equals(tm.getText()))
{
log.trace("Expected b but got " + tm.getText());
failed = true;
latch.release();
}
}
if (count == 7)
{
assertRemainingMessages(2);
if (!"c".equals(tm.getText()))
{
log.trace("Expected c but got " + tm.getText());
failed = true;
latch.release();
}
tm.acknowledge();
assertRemainingMessages(0);
latch.release();
}
}
catch (Exception e)
{
log.error("Caught exception", e);
failed = true;
latch.release();
}
}
}
private class MessageListenerTransactionalAck extends LatchListener
{
MessageListenerTransactionalAck(Session sess)
{
super(sess);
}
public void onMessage(Message m)
{
try
{
count++;
TextMessage tm = (TextMessage)m;
if (count == 1)
{
assertRemainingMessages(3);
if (!"a".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 2)
{
assertRemainingMessages(3);
if (!"b".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 3)
{
assertRemainingMessages(3);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
log.trace("Rollback");
sess.rollback();
}
if (count == 4)
{
assertRemainingMessages(3);
if (!"a".equals(tm.getText()))
{
failed = true;
latch.release();
}
}
if (count == 5)
{
assertRemainingMessages(3);
if (!"b".equals(tm.getText()))
{
failed = true;
latch.release();
}
log.trace("commit");
sess.commit();
assertRemainingMessages(1);
}
if (count == 6)
{
assertRemainingMessages(1);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
log.trace("recover");
sess.rollback();
}
if (count == 7)
{
assertRemainingMessages(1);
if (!"c".equals(tm.getText()))
{
failed = true;
latch.release();
}
log.trace("Commit");
sess.commit();
assertRemainingMessages(0);
latch.release();
}
}
catch (Exception e)
{
//log.error(e);
failed = true;
latch.release();
}
}
}
}