/*
* JBoss, Home of Professional Open Source.
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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.messagedriven.support;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.naming.NamingException;
import org.jboss.mx.util.ObjectNameFactory;
import org.jboss.naming.Util;
import org.jboss.test.JBossJMSTestCase;
import org.jboss.test.jms.JMSTestAdmin;
import org.jboss.test.messagedriven.mbeans.TestMessageDrivenManagementMBean;
import org.jboss.test.util.jms.JMSDestinationsUtil;
/**
* Basic tests of message driven beans
*
* @author <a href="mailto:adrian@jboss.com>Adrian Brock</a>
* @version <tt>$Revision: 1.4</tt>
*/
public abstract class BasicMessageDrivenUnitTest extends JBossJMSTestCase implements ExceptionListener
{
protected static final long WAIT_TIME = 5000L;
protected static final long REPEATED_WAIT = 4;
protected static ObjectName ejbParsingDeployer = ObjectNameFactory.create("jboss.ejb:service=EjbParsingDeployer");
protected static ObjectName testQueue = JMSTestAdmin.getAdmin().createQueueJMXName("testQueue");
protected static Properties testQueueProps = new Properties();
protected static Properties testQueueNoDestinationTypeProps = new Properties();
protected static ObjectName testTopic = JMSTestAdmin.getAdmin().createTopicJMXName("testTopic");
protected static Properties testTopicProps = new Properties();
protected static Properties testTopicNoDestinationTypeProps = new Properties();
protected static ObjectName testDurableTopic = JMSTestAdmin.getAdmin().createTopicJMXName("testDurableTopic");
protected static Properties testDurableTopicProps = new Properties();
protected static ObjectName dlqJMXDestination = JMSTestAdmin.getAdmin().createQueueJMXName("DLQ");
static
{
testQueueProps.put("destination", "testQueue");
testQueueProps.put("destinationType", "javax.jms.Queue");
testQueueNoDestinationTypeProps.put("destination", "testQueue");
testQueueNoDestinationTypeProps.put("destinationType", "");
testTopicProps.put("destination", "testTopic");
testTopicProps.put("destinationType", "javax.jms.Topic");
testTopicNoDestinationTypeProps.put("destination", "testTopic");
testTopicNoDestinationTypeProps.put("destinationType", "");
testDurableTopicProps.put("destination", "testDurableTopic");
testDurableTopicProps.put("destinationType", "javax.jms.Topic");
if (JMSDestinationsUtil.isHornetQ())
{
testDurableTopicProps.put("clientID", "DurableSubscriberExample");
}
testDurableTopicProps.put("durability", "Durable");
testDurableTopicProps.put("subscriptionName", "messagedriven");
testDurableTopicProps.put("user", "john");
testDurableTopicProps.put("password", "needle");
}
protected Thread thread;
protected boolean running = false;
protected String mdbjar = JMSDestinationsUtil.isJBM() ? "testmessagedriven.jar" : "testmessagedriven-hornetq.jar";
protected String mbeansar = "testmessagedriven.sar";
protected ObjectName jmxDestination = ObjectNameFactory.create("does:not=exist");
protected String connectionFactoryJNDI = "ConnectionFactory";
protected Destination destination;
protected Destination dlqDestination;
protected Properties defaultProps;
protected Properties props;
protected Connection connection;
protected Session session;
protected HashMap producers = new HashMap();
protected ArrayList<Object[]> messages = new ArrayList<Object[]>();
public BasicMessageDrivenUnitTest(String name, ObjectName jmxDestination, Properties defaultProps)
{
super(name);
this.jmxDestination = jmxDestination;
this.defaultProps = defaultProps;
}
public void runTest(Operation[] ops, Properties props) throws Exception
{
startTest(props);
try
{
for (int i = 0; i < ops.length; ++i)
{
try
{
ops[i].run();
}
catch (Throwable e)
{
log.warn(e.getMessage(), e);
throw new RuntimeException("Failure at operation " + i, e);
}
}
}
finally
{
stopTest();
}
}
public String getMDBDeployment()
{
return mdbjar;
}
public ObjectName getJMXDestination()
{
return jmxDestination;
}
public ObjectName getDLQJMXDestination()
{
return dlqJMXDestination;
}
public Destination getDestination() throws Exception
{
if (destination != null)
return destination;
String name = (String)getAttribute(getJMXDestination(), "Name");
destination = lookupDestination("/queue/" + name);
if (destination == null)
{
destination = lookupDestination("/topic/" + name);
}
if (destination == null)
{
destination = lookupDestination(name);
}
if (destination == null)
{
throw new NamingException("Can't find destination name " + name);
}
return destination;
}
private Destination lookupDestination(String jndi)
{
try
{
return (Destination) lookup(jndi, Destination.class);
}
catch (Exception e)
{
return null;
}
}
public Destination getDLQDestination() throws Exception
{
if (dlqDestination != null)
return dlqDestination;
String jndiName = "/queue/" + getAttribute(getDLQJMXDestination(), "Name");
dlqDestination = (Destination) lookup(jndiName, Destination.class);
return dlqDestination;
}
public MessageProducer getMessageProducer() throws Exception
{
return getMessageProducer(getDestination());
}
public MessageProducer getMessageProducer(Destination destination) throws Exception
{
MessageProducer producer = (MessageProducer) producers.get(destination);
if (producer == null)
producer = getSession().createProducer(destination);
return producer;
}
public Session getSession() throws Exception
{
if (session != null)
return session;
return getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE);
}
public Connection getConnection() throws Exception
{
if (connection != null)
return connection;
ConnectionFactory factory = (ConnectionFactory) lookup(connectionFactoryJNDI, ConnectionFactory.class);
connection = factory.createConnection();
connection.setExceptionListener(this);
return connection;
}
public Connection getConnection(String user, String password, String clientID) throws Exception
{
if (connection != null)
return connection;
ConnectionFactory factory = (ConnectionFactory) lookup(connectionFactoryJNDI, ConnectionFactory.class);
connection = factory.createConnection(user, password);
if (clientID != null)
{
connection.setClientID(clientID);
}
connection.setExceptionListener(this);
return connection;
}
// public Connection getConnection(String user, String password) throws Exception
// {
// return getConnection(user, password, null);
// }
//
public void onException(JMSException e)
{
log.debug("Notified of error", e);
Connection temp = connection;
connection = null;
try
{
if (temp != null)
temp.close();
}
catch (JMSException ignored)
{
log.debug("Ignored ", ignored);
}
}
public TextMessage getTestMessage() throws Exception
{
return getSession().createTextMessage();
}
protected void deployDestinations() throws Exception
{
JMSDestinationsUtil.destroyDestinations();
JMSDestinationsUtil.setupBasicDestinations();
}
protected void setUp() throws Exception
{
super.setUp();
if (isDeployDestinations())
deployDestinations();
try
{
deploy(mbeansar);
}
catch (Exception e)
{
if (isDeployDestinations())
undeployDestinations();
throw e;
}
}
protected void tearDown() throws Exception
{
try
{
undeploy(mbeansar);
}
catch (Throwable t)
{
getLog().error("Error undeploying: " + mbeansar, t);
}
if (isDeployDestinations())
JMSDestinationsUtil.destroyDestinations();
super.tearDown();
}
protected boolean isDeployDestinations()
{
return true;
}
protected boolean isClearDestination()
{
return true;
}
protected void startTest(Properties props) throws Exception
{
this.props = props;
if (isClearDestination())
clearMessages(getJMXDestination());
clearMessages(getDLQJMXDestination());
tidyup(props);
initProperties(props);
deploy(getMDBDeployment());
try
{
// // FIXME Need to wait for asynchrounous bootstrap of container
Thread.sleep(5000);
startReceiverThread();
}
catch (Exception e)
{
undeploy(getMDBDeployment());
throw e;
}
}
protected void stopTest()
{
if (connection != null)
{
try
{
connection.close();
}
catch (Exception ignored)
{
}
connection = null;
}
stopReceiverThread();
try
{
undeploy(getMDBDeployment());
}
catch (Throwable t)
{
getLog().error("Error undeploying: " + getMDBDeployment(), t);
}
try
{
if (isClearDestination())
clearMessages(getJMXDestination());
tidyup(props);
}
catch (Throwable t)
{
getLog().error("Error clearing messages: " + getJMXDestination(), t);
}
try
{
clearMessages(getDLQJMXDestination());
}
catch (Throwable t)
{
getLog().error("Error clearing messages: " + getDLQJMXDestination(), t);
}
try
{
JMSDestinationsUtil.destroyDestinations();
}
catch (Throwable t)
{
getLog().error("Error Destroying Queues", t);
}
}
protected void clearMessages(ObjectName name) throws Exception
{
if (name != null)
{
getLog().info("Clearing messages " + name);
try
{
getServer().invoke(name, "removeMessages", new Object[]{""}, new String[]{String.class.getName()});
}
catch (Throwable e)
{
// This is a work-around for https://jira.jboss.org/jira/browse/HORNETQ-376
// It has been fixed on hornetQ. This line could be removed we upgraded HornetQ from 2.1.0.Beta3
log.warn("Couldn't remove messages from " + name, e);
}
}
}
protected void tidyup(Properties props) throws Exception
{
String name = props.getProperty("subscriptionName");
if (name != null)
{
String user = props.getProperty("user");
String clientID = props.getProperty("clientID");
log.info("ClientID = " + clientID + " on tidyUP");
if (user != null)
{
log.info("Getting connection with clientID");
String password = props.getProperty("password");
getConnection(user, password, clientID);
}
else
getConnection();
try
{
Session session = getSession();
try
{
session.unsubscribe(name);
}
catch (Throwable t)
{
log.warn("Unsubscribe failed: ", t);
}
}
finally
{
try
{
connection.close();
}
catch (Exception ignored)
{
}
connection = null;
}
}
}
protected void activate(ObjectName name) throws Exception
{
getServer().invoke(name, "startDelivery", new Object[0], new String[0]);
}
protected void deactivate(ObjectName name) throws Exception
{
getServer().invoke(name, "stopDelivery", new Object[0], new String[0]);
}
protected void start(ObjectName name) throws Exception
{
getServer().invoke(name, "create", new Object[0], new String[0]);
getServer().invoke(name, "start", new Object[0], new String[0]);
}
protected void stop(ObjectName name) throws Exception
{
getServer().invoke(name, "stop", new Object[0], new String[0]);
getServer().invoke(name, "destroy", new Object[0], new String[0]);
}
protected void initProperties(Properties props) throws Exception
{
getLog().info("Init properties " + props);
getServer().invoke(TestMessageDrivenManagementMBean.OBJECT_NAME, "initProperties", new Object[] { props }, new String[] { Properties.class.getName() });
}
protected void waitMessages(int expected, long wait) throws Exception
{
synchronized (this)
{
if (wait != 0)
wait(wait);
for (int i = 0; i < REPEATED_WAIT && messages.size() < expected; ++i)
wait(WAIT_TIME);
}
}
protected ArrayList<Object[]> getMessages() throws Exception
{
synchronized (this)
{
return new ArrayList<Object[]>(messages);
}
}
protected void startReceiverThread()
{
synchronized (this)
{
thread = new Thread(new ReceiverRunnable(), getClass().getName());
thread.start();
running = true;
}
}
protected void stopReceiverThread()
{
synchronized (this)
{
running = false;
while (thread != null)
{
try
{
this.notifyAll();
this.wait();
}
catch (Throwable t)
{
getLog().error("Error waiting for receiver thread to stop " + thread, t);
}
}
}
}
protected Object getAttribute(ObjectName name, String attribute) throws Exception
{
return getServer().getAttribute(name, attribute);
}
protected Object lookup(String jndiName, Class clazz) throws Exception
{
return Util.lookup(getInitialContext(), jndiName, clazz);
}
public class ReceiverRunnable implements Runnable
{
public void run()
{
try
{
while (true)
{
ArrayList result = (ArrayList) getAttribute(TestMessageDrivenManagementMBean.OBJECT_NAME, "Messages");
log.info("Trying to get more results " + result.size());
synchronized (BasicMessageDrivenUnitTest.this)
{
if (running == false)
break;
if (result.size() > 0)
{
messages.addAll(result);
BasicMessageDrivenUnitTest.this.notifyAll();
}
BasicMessageDrivenUnitTest.this.wait(WAIT_TIME);
}
}
}
catch (Throwable t)
{
getLog().error("Error in receiver thread " + thread, t);
}
synchronized (BasicMessageDrivenUnitTest.this)
{
thread = null;
BasicMessageDrivenUnitTest.this.notifyAll();
}
}
}
}