package org.activemq.usecases;
import junit.framework.TestCase;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import javax.jms.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.derby.jdbc.EmbeddedDataSource;
import org.activemq.ActiveMQConnection;
import org.activemq.ActiveMQConnectionFactory;
import org.activemq.message.ActiveMQMessage;
import org.activemq.util.IdGenerator;
import org.activemq.broker.impl.BrokerConnectorImpl;
import org.activemq.broker.impl.BrokerContainerImpl;
import org.activemq.io.impl.DefaultWireFormat;
import org.activemq.store.PersistenceAdapter;
import org.activemq.store.jdbc.JDBCPersistenceAdapter;
public class SystemTest extends TestCase implements MessageListener {
private static final Logger log = LoggingManager.getLoggerForClass();
public static final String ACTIVEMQ_SERVER = "ActiveMQ Server";
public static final boolean TRANSACTED_FALSE = false;
public static final String TOOL_DEFAULT = "TOOL.DEFAULT";
public static final String LAST_MESSAGE = "LAST";
private static int msgCounter = 0;
public static Map ProducerMap = Collections.synchronizedMap(new HashMap());
private int producerCount = 0;
private int consumerCount = 0;
private int subjectCount = 0;
private int messageCount = 0;
private boolean isPersistent = true;
private boolean isDurable = true;
private boolean isTopic = true;
private boolean isEmbeddedBroker = true;
private boolean init = false;
private boolean testStillRunning = true;
private BrokerContainerImpl broker = null;
private String brokerUrl = null;
private MessageConsumer consumer = null;
/**
* Default constructor
*/
protected SystemTest(){
super();
brokerUrl = "tcp://localhost:6099";
isEmbeddedBroker = true;
ProducerMap.clear();
msgCounter = 0;
init = false;
consumer = null;
testStillRunning = true;
}
/**
* Constructor
*
* @param isTopic - true when topic, false when queue.
* @parm isPersistent - true when the delivery mode is persistent.
* @param isDurable - true when the suscriber is durable(For topic only).
* @param producerCount - number of producers.
* @param consumerCount - number of consumers.
* @param subjectCount - number of destinations.
* @param messageCount - number of messages to be delivered.
* @param testTitle - test title/name.
*
*/
protected SystemTest(boolean isTopic,
boolean isPersistent,
boolean isDurable,
int producerCount,
int consumerCount,
int subjectCount,
int messageCount,
String testTitle){
super();
this.isTopic = isTopic;
this.isPersistent = isPersistent;
this.isDurable = isDurable;
this.producerCount = producerCount;
this.consumerCount = consumerCount;
this.subjectCount = subjectCount;
this.messageCount = messageCount;
this.testParameterSettings(testTitle);
brokerUrl = "tcp://localhost:6099";
isEmbeddedBroker = true;
ProducerMap.clear();
msgCounter = 0;
init = false;
consumer = null;
testStillRunning = true;
}
/*
* Producer section
*/
/**
* Creates the message producer threads.
*/
protected void publish() throws JMSException {
String subjects[] = getSubjects();
for (int i = 0; i < producerCount; i++) {
final int x = i;
final String subject = subjects[i % subjects.length];
Thread thread = new Thread() {
public void run() {
try {
publish(x, subject);
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
/**
* Creates the producer and send the messages.
*
* @param x - producer number.
* @param subject - the destination where the messages will be sent.
*/
protected void publish(int x, String subject) throws Exception {
MessageProducer publisher = null;
Connection connection = createConnectionFactory(brokerUrl, isEmbeddedBroker);
if (isPersistent) {
IdGenerator idGenerator = new IdGenerator();
connection.setClientID(idGenerator.generateId());
}
Session session = createSession(connection, TRANSACTED_FALSE);
Destination destination = createDestination(session, subject, isTopic);
publisher = session.createProducer(destination);
if (isPersistent) {
publisher.setDeliveryMode(DeliveryMode.PERSISTENT);
} else {
publisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
StringBuffer sb = new StringBuffer();
sb.append("PROD");
sb.append(x);
sb.append("#BODY");
//Sending messages
for (int i = 0; i < messageCount - 1; ++i) {
TextMessage message = session.createTextMessage(sb.toString());
publisher.send(message);
}
sb.delete(0, sb.length());
//Sending the last message
sb.append("PROD");
sb.append(x);
sb.append("#");
sb.append(LAST_MESSAGE);
TextMessage message = session.createTextMessage(sb.toString());
publisher.send(message);
}
/*
* Consumer section
*/
/**
* Generates the topic/queue destinations.
*
* @return String[] - topic/queue destination name.
*/
protected String[] getSubjects() {
//Create the subjects.
String[] subjects = new String[subjectCount];
//Appended to the subject to determine if its a queue or topic.
String prefix = null;
if (this.isTopic) {
prefix = ".TOPIC";
} else {
prefix = ".QUEUE";
}
for (int i = 0; i < subjects.length; i++) {
subjects[i] = TOOL_DEFAULT + prefix + i;
}
return subjects;
}
/**
* Suscribes the consumers to the topic/queue destinations.
*/
protected void subscribe() throws JMSException {
String subjects[] = getSubjects();
for (int i = 0; i < consumerCount; i++) {
String subject = subjects[i % subjectCount];
subscribe(subject);
}
}
/**
* Suscribes the consumer to the topic/queue specified by the subject.
*
* @param subject - the Destination where the consumer waits upon for messages.
*/
protected void subscribe(String subject) throws JMSException {
Connection connection = createConnectionFactory(brokerUrl, isEmbeddedBroker);
if (isDurable) {
IdGenerator idGenerator = new IdGenerator();
connection.setClientID(idGenerator.generateId());
}
//Start the connection before receiving messages.
connection.start();
Session session = createSession(connection, TRANSACTED_FALSE);
Destination destination = createDestination(session, subject, isTopic);
if (isDurable && isTopic) {
consumer = session.createDurableSubscriber((Topic) destination, getClass().getName());
} else {
consumer = session.createConsumer(destination);
}
consumer.setMessageListener(this);
}
/**
* Processes the received message.
*
* @param message - message received by the listener.
*/
public void onMessage(Message message) {
try {
ActiveMQMessage amsg = (ActiveMQMessage) message;
TextMessage textMessage = (TextMessage) message;
StringBuffer sb = new StringBuffer();
sb.append(textMessage.getText());
sb.append("#");
sb.append(amsg.getConsumerIdentifer());
msgCounter++;
String strMsgCounter = String.valueOf(msgCounter);
ProducerMap.put(strMsgCounter, sb.toString());
} catch (JMSException e) {
//log.error("Unable to force deserialize the content", e);
}
}
/**
* Validates the result of the producing and consumption of messages by the server.
* It checks for duplicate messages, message count and order.
*/
protected synchronized void timerLoop() {
System.out.println("MessagingSystemTest.timerLoop() * started * ");
Map ProducerTextMap = new HashMap();
Map currentProducerMap = null;
String producerName = null;
String msgBody = null;
String consumerName = null;
String mapKey = null;
int expectedNoOfMessages = messageCount;
boolean dowhile = true;
while (dowhile) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Retrieve the map containing the received messages data
currentProducerMap = resetProducerMap();
if (currentProducerMap.size() == 0) {
dowhile = false;
}
//Put the map values to another map for parsing.
for (int i = 1; i <= currentProducerMap.size(); i++) {
String ProdMsg = (String) currentProducerMap.get(String.valueOf(i));
producerName = ProdMsg.substring(0, ProdMsg.indexOf("#"));
msgBody = ProdMsg.substring(ProdMsg.indexOf("#") + 1, ProdMsg.lastIndexOf("#"));
consumerName = ProdMsg.substring(ProdMsg.lastIndexOf("#"), ProdMsg.length());
if (isTopic) {
mapKey = consumerName + producerName;
} else {
mapKey = producerName;
}
if (ProducerTextMap.containsKey(mapKey)) {
//Increment the counter value
Integer value = (Integer) ProducerTextMap.get(mapKey);
ProducerTextMap.put(mapKey, new Integer(value.intValue() + 1));
} else {
//Put the Producer Name in the map
ProducerTextMap.put(mapKey, new Integer(1));
}
Integer messageCounter = (Integer) ProducerTextMap.get(mapKey);
//Checks for duplicate messages.
if (messageCounter.intValue() > expectedNoOfMessages) {
assertTrue("Should have received message duplicates!", messageCounter.intValue() <= expectedNoOfMessages);
if (messageCounter.intValue() > expectedNoOfMessages) {
System.out.println("Should have received message duplicates!");
}
break;
} else if (LAST_MESSAGE.equals(msgBody)) {
System.out.println("entered MsgBody.equals(LAST_MESSAGE)..." + mapKey +
" " + messageCounter.intValue() +"=" + expectedNoOfMessages);
// Validates that the messages received is equal to the number
// of expected messages
if (messageCounter.intValue() != expectedNoOfMessages) {
System.out.println("entered messageCounter.intValue() != expectedNoOfMessages...");
// Checks for message order.
assertTrue("Should have received messages in order!", messageCounter.intValue() == expectedNoOfMessages);
if (messageCounter.intValue() != expectedNoOfMessages) {
System.out.println("Should have received messages in order!");
}
break;
} else if (currentProducerMap.size() == i) {
System.out.println("MessagingSystemTest.timerLoop() says system_test_pass!!!... ");
break;
}
}
}
}
testStillRunning = false;
System.out.println("MessagingSystemTest.timerLoop() * ended * ");
}
/**
* Returns the message entries and clears the map for another set
* of messages to be processed.
*
* @return Map - messages to be processed.
*/
protected synchronized Map resetProducerMap() {
Map copy = Collections.synchronizedMap(new HashMap(ProducerMap));
ProducerMap.clear();
msgCounter = 0;
return copy;
}
/*
* Utility section
*/
/**
* Creates the connection to the broker.
*
* @param url - broker url.
* @param embeddedBroker - true if an embedded broker will be used.
* @return Connection - broker connection.
*/
private static Connection createConnectionFactory(String url,
boolean embeddedBroker) throws JMSException {
//Used to create a session from the default MQ server ActiveMQConnectionFactory.
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
if (embeddedBroker) {
factory.setUseEmbeddedBroker(true);
}
factory.setTurboBoost(true);
ActiveMQConnection c = (ActiveMQConnection) factory.createConnection();
c.getPrefetchPolicy().setQueuePrefetch(1000);
c.getPrefetchPolicy().setQueueBrowserPrefetch(1000);
c.getPrefetchPolicy().setTopicPrefetch(1000);
c.getPrefetchPolicy().setDurableTopicPrefetch(1000);
return c;
}
/**
* Creates the connection session.
*
* @param connection - broker connection.
* @param isTransacted - true if the session will be session transacted.
* otherwise the the session will be using auto acknowledge.
* @return Session - connection session.
*/
private static Session createSession(Connection connection,
boolean isTransacted) throws JMSException {
if (isTransacted) {
return connection.createSession(true, Session.SESSION_TRANSACTED);
} else {
return connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
}
}
/**
* Creates the session destination.
*
* @param session - connection session.
* @param subject - destination name.
* @param isTopic - true if the destination is a topic,
* otherwise the destination is a queue.
* @return Destination - session destination.
*/
private static Destination createDestination(Session session,
String subject,
boolean isTopic) throws JMSException {
if (isTopic) {
return session.createTopic(subject);
} else {
return session.createQueue(subject);
}
}
/*
* Unit test section
*/
/**
* Sets up the resources of the unit test.
*
* @throws Exception
*/
protected void setUp() throws Exception {
//Set up the broker
createBroker();
}
/**
* Clears up the resources used in the unit test.
*/
protected void tearDown() throws Exception {
//Shut down the broker
destoryBroker();
}
/**
* Executes the unit test by running the producers and consumers.
* It checks for duplicate messages, message count and order.
*/
protected void doTest() throws Exception {
System.out.println("MessagingSystemTest.doTest() * start *");
//Set up the consumers
subscribe();
System.out.println("MessagingSystemTest.doTest() after suscribe()...");
//Set up the producers
publish();
System.out.println("MessagingSystemTest.doTest() after publish()...");
//Run the test
Thread timer = new Thread() {
public void run() {
timerLoop();
}
};
timer.setPriority(Thread.MIN_PRIORITY);
timer.start();
while (testStillRunning) {
try {
if (Thread.currentThread() == timer) {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("MessagingSystemTest.doTest() * end *");
}
/**
* Sets up and starts the broker.
*/
private void createBroker() throws Exception {
broker = new BrokerContainerImpl("localhost");
broker.addConnector(new BrokerConnectorImpl(broker, "vm://localhost", new DefaultWireFormat()));
broker.setPersistenceAdapter(createPersistenceAdapter());
broker.start();
}
/**
* Closes the broker.
*/
private void destoryBroker() throws Exception {
if (broker != null) {
broker.stop();
}
}
/**
* Returns the persistence adapter.
* Sets up the testing database to be used when the messages are persistent.
* It attempts to recreate the tables everytime the test is executed.
*
* @return PersistenceAdapter - persistence adapter.
*/
protected PersistenceAdapter createPersistenceAdapter() {
EmbeddedDataSource ds = new EmbeddedDataSource();
ds.setDatabaseName("testdb");
if (!init) {
ds.setCreateDatabase("create");
}
JDBCPersistenceAdapter persistenceAdapter = new JDBCPersistenceAdapter(ds, new DefaultWireFormat());
if (!init) {
persistenceAdapter.setDropTablesOnStartup(true);
}
init = true;
return persistenceAdapter;
}
/**
* Prints the test settings.
*
* @param strTestTitle - unit test name.
*/
public void testParameterSettings(String strTestTitle) {
System.out.println(strTestTitle);
System.out.println("============================================================");
System.out.println("Test settings:");
System.out.println("isTopic=" + new Boolean(isTopic).toString());
System.out.println("isPersistent=" + new Boolean(isPersistent).toString());
System.out.println("isDurable=" + new Boolean(isDurable).toString());
System.out.println("producerCount=" + producerCount);
System.out.println("consumerCount=" + consumerCount);
System.out.println("subjectCount=" + subjectCount);
System.out.println("messageCount=" + messageCount);
System.out.println("");
}
}