/*
* JBoss, Home of Professional Open Source
* Copyright 2005-2008, Red Hat Middleware LLC, and individual contributors
* 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.tools.container;
import org.jboss.kernel.spi.deployment.KernelDeployment;
import org.jboss.messaging.core.config.TransportConfiguration;
import org.jboss.messaging.core.logging.Logger;
import org.jboss.messaging.core.postoffice.Binding;
import org.jboss.messaging.core.security.Role;
import org.jboss.messaging.core.server.MessagingServer;
import org.jboss.messaging.core.settings.impl.QueueSettings;
import org.jboss.messaging.jms.JBossDestination;
import org.jboss.messaging.jms.server.JMSServerManager;
import org.jboss.messaging.jms.server.management.JMSQueueControlMBean;
import org.jboss.messaging.jms.server.management.SubscriptionInfo;
import org.jboss.messaging.jms.server.management.TopicControlMBean;
import org.jboss.messaging.jms.server.management.impl.JMSManagementServiceImpl;
import org.jboss.messaging.microcontainer.JBMBootstrapServer;
import org.jboss.messaging.util.SimpleString;
import org.jboss.test.messaging.tools.ConfigurationHelper;
import org.jboss.test.messaging.tools.ServerManagement;
import org.jboss.test.messaging.tools.jboss.MBeanConfigurationElement;
import org.jboss.tm.TransactionManagerLocator;
import javax.management.MBeanServerInvocationHandler;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Set;
/**
* @author <a href="mailto:ovidiu@feodorov.com">Ovidiu Feodorov</a>
* @author <a href="mailto:tim.fox@jboss.com">Tim Fox</a>
* @version <tt>1.1</tt>
* <p/>
* LocalTestServer.java,v 1.1 2006/02/21 08:25:32 timfox Exp
*/
public class LocalTestServer implements Server, Runnable
{
// Constants ------------------------------------------------------------------------------------
private static final Logger log = Logger.getLogger(LocalTestServer.class);
private boolean started = false;
private HashMap<String, List<String>> allBindings = new HashMap<String, List<String>>();
// Static ---------------------------------------------------------------------------------------
public static void setEnvironmentServerIndex(int serverIndex)
{
System.setProperty(Constants.SERVER_INDEX_PROPERTY_NAME, Integer.toString(serverIndex));
}
public static void clearEnvironmentServerIndex()
{
System.getProperty(Constants.SERVER_INDEX_PROPERTY_NAME, null);
}
// Attributes -----------------------------------------------------------------------------------
private ServiceContainer sc;
// the server MBean itself
private ObjectName serverPeerObjectName;
private int serverIndex;
JBMBootstrapServer bootstrap;
// Constructors ---------------------------------------------------------------------------------
public LocalTestServer()
{
super();
}
public LocalTestServer(int serverIndex)
{
this();
this.serverIndex = serverIndex;
}
// Server implementation ------------------------------------------------------------------------
public int getServerID()
{
return serverIndex;
}
public synchronized void start(String[] containerConfig,
HashMap<String, Object> configuration,
boolean clearDatabase) throws Exception
{
if (isStarted())
{
return;
}
log.info("** deleting database?" + clearDatabase);
if (clearDatabase)
{
//Delete the BDB environment
File dir = new File("data");
boolean deleted = deleteDirectory(dir);
log.info("Deleted dir: " + dir.getAbsolutePath() + " deleted: " + deleted);
}
ConfigurationHelper.addServerConfig(getServerID(), configuration);
JBMPropertyKernelConfig propertyKernelConfig = new JBMPropertyKernelConfig(System.getProperties());
//propertyKernelConfig.setServerID(getServerID());
bootstrap = new JBMBootstrapServer(containerConfig, propertyKernelConfig);
System.setProperty(Constants.SERVER_INDEX_PROPERTY_NAME, ""+getServerID());
bootstrap.run();
started = true;
}
private static boolean deleteDirectory(File directory)
{
if (directory.isDirectory())
{
String[] files = directory.list();
for (int j = 0; j < files.length; j++)
{
if (!deleteDirectory(new File(directory, files[j])))
{
return false;
}
}
}
return directory.delete();
}
protected void deleteAllData() throws Exception
{
log.info("DELETING ALL DATA FROM DATABASE!");
InitialContext ctx = getInitialContext();
// We need to execute each drop in its own transaction otherwise postgresql will not execute
// further commands after one fails
TransactionManager mgr = TransactionManagerLocator.locateTransactionManager();
DataSource ds = (DataSource) ctx.lookup("java:/DefaultDS");
javax.transaction.Transaction txOld = mgr.suspend();
executeStatement(mgr, ds, "DELETE FROM JBM_POSTOFFICE");
executeStatement(mgr, ds, "DELETE FROM JBM_MSG_REF");
executeStatement(mgr, ds, "DELETE FROM JBM_MSG");
executeStatement(mgr, ds, "DELETE FROM JBM_TX");
executeStatement(mgr, ds, "DELETE FROM JBM_COUNTER");
executeStatement(mgr, ds, "DELETE FROM JBM_USER");
executeStatement(mgr, ds, "DELETE FROM JBM_ROLE");
if (txOld != null)
{
mgr.resume(txOld);
}
log.debug("done with the deleting data");
}
private void executeStatement(TransactionManager mgr, DataSource ds, String statement) throws Exception
{
Connection conn = null;
boolean exception = false;
try
{
try
{
mgr.begin();
conn = ds.getConnection();
log.debug("executing " + statement);
PreparedStatement ps = conn.prepareStatement(statement);
ps.executeUpdate();
log.debug(statement + " executed");
ps.close();
}
catch (SQLException e)
{
// Ignore
log.debug("Failed to execute statement", e);
exception = true;
}
}
finally
{
if (conn != null)
{
conn.close();
}
if (exception)
{
mgr.rollback();
}
else
{
mgr.commit();
}
}
}
public synchronized boolean stop() throws Exception
{
bootstrap.shutDown();
started=false;
unbindAll();
return true;
}
public void ping() throws Exception
{
if (!isStarted())
{
throw new RuntimeException("ok");
}
}
public synchronized void kill() throws Exception
{
stop();
}
public KernelDeployment deploy(String resourceName) throws Exception
{
try
{
return bootstrap.deploy(resourceName);
}
catch (Throwable e)
{
// RMI can only throw Exception or its subclasses... This is case we ever implement Server as remote again
if (e instanceof Exception)
{
throw (Exception)e;
}
else
{
throw new Exception (e.toString(), e);
}
}
}
public KernelDeployment deployXML(String name, String xml) throws Exception
{
try
{
return bootstrap.deploy(name, xml);
}
catch (Throwable e)
{
// RMI can only throw Exception or its subclasses... This is case we ever implement Server as remote again
if (e instanceof Exception)
{
throw (Exception)e;
}
else
{
throw new Exception (e.toString(), e);
}
}
}
public void undeploy(KernelDeployment deployment) throws Exception
{
try
{
bootstrap.undeploy(deployment);
}
catch (Throwable e)
{
// RMI can only throw Exception or its subclasses... This is case we ever implement Server as remote again
if (e instanceof Exception)
{
throw (Exception)e;
}
else
{
throw new Exception (e.toString(), e);
}
}
}
public Object getAttribute(ObjectName on, String attribute) throws Exception
{
return null;// sc.getAttribute(on, attribute);
}
public void setAttribute(ObjectName on, String name, String valueAsString) throws Exception
{
//sc.setAttribute(on, name, valueAsString);
}
public Object invoke(ObjectName on, String operationName, Object[] params, String[] signature)
throws Exception
{
return null;//sc.invoke(on, operationName, params, signature);
}
public void addNotificationListener(ObjectName on, NotificationListener listener)
throws Exception
{
// sc.addNotificationListener(on, listener);
}
public void removeNotificationListener(ObjectName on, NotificationListener listener)
throws Exception
{
//sc.removeNotificationListener(on, listener);
}
public void log(int level, String text)
{
if (ServerManagement.FATAL == level)
{
log.fatal(text);
}
else if (ServerManagement.ERROR == level)
{
log.error(text);
}
else if (ServerManagement.WARN == level)
{
log.warn(text);
}
else if (ServerManagement.INFO == level)
{
log.info(text);
}
else if (ServerManagement.DEBUG == level)
{
log.debug(text);
}
else if (ServerManagement.TRACE == level)
{
log.trace(text);
}
else
{
// log everything else as INFO
log.info(text);
}
}
public synchronized boolean isStarted() throws Exception
{
return started;
}
public synchronized void startServerPeer(int serverPeerID,
String defaultQueueJNDIContext,
String defaultTopicJNDIContext,
ServiceAttributeOverrides attrOverrides,
boolean clustered) throws Exception
{
System.setProperty(Constants.SERVER_INDEX_PROPERTY_NAME, "" + getServerID());
getMessagingServer().start();
}
public synchronized void stopServerPeer() throws Exception
{
System.setProperty(Constants.SERVER_INDEX_PROPERTY_NAME, "" + getServerID());
getMessagingServer().stop();
//also unbind everything
unbindAll();
}
private void unbindAll()
throws Exception
{
Collection<List<String>> bindings = allBindings.values();
for (List<String> binding : bindings)
{
for (String s : binding)
{
getInitialContext().unbind(s);
}
}
}
public boolean isServerPeerStarted() throws Exception
{
return this.getJMSServerManager().isStarted();
}
public ObjectName getServerPeerObjectName()
{
return serverPeerObjectName;
}
/**
* Only for in-VM use!
*/
public MessagingServer getServerPeer()
{
return getMessagingServer();
}
public void destroyQueue(String name, String jndiName) throws Exception
{
this.getJMSServerManager().destroyQueue(name);
}
public void destroyTopic(String name, String jndiName) throws Exception
{
this.getJMSServerManager().destroyTopic(name);
}
public void createQueue(String name, String jndiName) throws Exception
{
this.getJMSServerManager().createQueue(name, "/queue/" + (jndiName != null ? jndiName : name));
}
public void createTopic(String name, String jndiName) throws Exception
{
this.getJMSServerManager().createTopic(name, "/topic/" + (jndiName != null ? jndiName : name));
}
public void deployConnectionFactory(String clientId, String objectName,
List<String> jndiBindings) throws Exception
{
deployConnectionFactory(clientId, objectName, jndiBindings, -1, -1, -1, -1, false, false, -1, false);
}
public void deployConnectionFactory(String objectName,
List<String> jndiBindings,
int consumerWindowSize) throws Exception
{
deployConnectionFactory(null, objectName, jndiBindings, consumerWindowSize, -1, -1, -1, false, false, -1, false);
}
public void deployConnectionFactory(String objectName,
List<String> jndiBindings) throws Exception
{
deployConnectionFactory(null, objectName, jndiBindings, -1, -1, -1, -1, false, false, -1, false);
}
public void deployConnectionFactory(String objectName,
List<String> jndiBindings,
int prefetchSize,
int defaultTempQueueFullSize,
int defaultTempQueuePageSize,
int defaultTempQueueDownCacheSize) throws Exception
{
this.deployConnectionFactory(null, objectName, jndiBindings, prefetchSize, defaultTempQueueFullSize,
defaultTempQueuePageSize, defaultTempQueueDownCacheSize, false, false, -1, false);
}
public void deployConnectionFactory(String objectName,
List<String> jndiBindings,
boolean supportsFailover, boolean supportsLoadBalancing) throws Exception
{
this.deployConnectionFactory(null, objectName, jndiBindings, -1, -1,
-1, -1, supportsFailover, supportsLoadBalancing, -1, false);
}
public void deployConnectionFactory(String clientId,
String objectName,
List<String> jndiBindings,
int prefetchSize,
int defaultTempQueueFullSize,
int defaultTempQueuePageSize,
int defaultTempQueueDownCacheSize,
boolean supportsFailover,
boolean supportsLoadBalancing,
int dupsOkBatchSize,
boolean blockOnAcknowledge) throws Exception
{
log.info("deploying connection factory with name: " + objectName + " and dupsok: " + dupsOkBatchSize);
getJMSServerManager().createConnectionFactory(objectName,
new TransportConfiguration("org.jboss.messaging.core.remoting.impl.netty.NettyConnectorFactory"), null, 5000, 5000,
clientId, dupsOkBatchSize,
prefetchSize, -1, 1000, -1, blockOnAcknowledge, true, true, false, jndiBindings);
}
public void undeployConnectionFactory(String objectName) throws Exception
{
getJMSServerManager().destroyConnectionFactory(objectName);
}
public void configureSecurityForDestination(String destName, boolean isQueue, Set<Role> roles) throws Exception
{
String destination = (isQueue ? "queuejms." : "topicjms.") + destName;
if (roles != null)
{
getMessagingServer().getSecurityRepository().addMatch(destination, roles);
}
else
{
getMessagingServer().getSecurityRepository().removeMatch(destination);
}
}
public Object executeCommand(Command command) throws Exception
{
return command.execute(this);
}
public UserTransaction getUserTransaction() throws Exception
{
//return sc.getUserTransaction();
return null;
}
public List pollNotificationListener(long listenerID) throws Exception
{
throw new IllegalStateException("Poll doesn't make sense on a local server. " +
"Register listeners directly instead.");
}
public void flushManagedConnectionPool()
{
//sc.flushManagedConnectionPool();
}
// Public ---------------------------------------------------------------------------------------
// Package protected ----------------------------------------------------------------------------
// Protected ------------------------------------------------------------------------------------
protected ServiceContainer getServiceContainer()
{
return sc;
}
protected void overrideServerPeerConfiguration(MBeanConfigurationElement config,
int serverPeerID, String defaultQueueJNDIContext, String defaultTopicJNDIContext)
throws Exception
{
config.setAttribute("ServerPeerID", Integer.toString(serverPeerID));
config.setAttribute("DefaultQueueJNDIContext",
defaultQueueJNDIContext == null ? "/queue" : defaultQueueJNDIContext);
config.setAttribute("DefaultTopicJNDIContext",
defaultTopicJNDIContext == null ? "/topic" : defaultTopicJNDIContext);
}
// Private --------------------------------------------------------------------------------------
public MessagingServer getMessagingServer()
{
return (MessagingServer) bootstrap.getKernel().getRegistry().getEntry("MessagingServer").getTarget();
}
public JMSServerManager getJMSServerManager()
{
return (JMSServerManager) bootstrap.getKernel().getRegistry().getEntry("JMSServerManager").getTarget();
}
public void addQueueSettings(String name, long redeliveryDelay)
{
QueueSettings qs = getMessagingServer().getQueueSettingsRepository().getMatch("*");
QueueSettings newSets = new QueueSettings();
newSets.setRedeliveryDelay(redeliveryDelay);
newSets.merge(qs);
getMessagingServer().getQueueSettingsRepository().addMatch(name, newSets);
}
public void removeQueueSettings(String name)
{
getMessagingServer().getQueueSettingsRepository().removeMatch(name);
}
public InitialContext getInitialContext() throws Exception
{
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jboss.test.messaging.tools.container.InVMInitialContextFactory");
props.setProperty(Constants.SERVER_INDEX_PROPERTY_NAME, "" + getServerID());
//props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
return new InitialContext(props);
}
public void run()
{
bootstrap.run();
started = true;
synchronized (this)
{
notify();
try
{
wait();
}
catch (InterruptedException e)
{
//e.printStackTrace();
}
}
}
public Integer getMessageCountForQueue(String queueName) throws Exception
{
ObjectName objectName = JMSManagementServiceImpl.getJMSQueueObjectName(queueName);
JMSQueueControlMBean queue = (JMSQueueControlMBean)getMessagingServer().getManagementService().getResource(objectName);
if (queue != null)
{
return queue.getMessageCount();
} else
{
return -1;
}
}
public void removeAllMessages(JBossDestination destination) throws Exception
{
Binding binding = getMessagingServer().getPostOffice().getBinding(destination.getSimpleAddress());
if (binding != null)
{
binding.getQueue().deleteAllReferences(getMessagingServer().getStorageManager());
}
}
public List<SubscriptionInfo> listAllSubscribersForTopic(String s) throws Exception
{
ObjectName objectName = JMSManagementServiceImpl.getJMSTopicObjectName(s);
TopicControlMBean topic = (TopicControlMBean) MBeanServerInvocationHandler.newProxyInstance(
ManagementFactory.getPlatformMBeanServer(), objectName, TopicControlMBean.class, false);
return Arrays.asList(topic.listAllSubscriptionInfos());
}
public Set<Role> getSecurityConfig() throws Exception
{
return getMessagingServer().getSecurityRepository().getMatch("*");
}
public void setSecurityConfig(Set<Role> defConfig) throws Exception
{
getMessagingServer().getSecurityRepository().removeMatch("*");
getMessagingServer().getSecurityRepository().addMatch("*", defConfig);
}
public void setRedeliveryDelayOnDestination(String dest, boolean queue, long delay) throws Exception
{
SimpleString condition = new SimpleString((queue ? "queuejms." : "topicjms.") + dest);
QueueSettings queueSettings = new QueueSettings();
queueSettings.setRedeliveryDelay(delay);
//FIXME we need to expose queue attributes in another way
// getMessagingServer().getServerManagement().setQueueAttributes(condition, queueSettings);
}
// Inner classes --------------------------------------------------------------------------------
}