net.timewalker.ffmq4.local.FFMQEngine.java Source code

Java tutorial

Introduction

Here is the source code for net.timewalker.ffmq4.local.FFMQEngine.java

Source

/*
 * This file is part of FFMQ.
 *
 * FFMQ 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 of the License, or
 * (at your option) any later version.
 *
 * FFMQ 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 FFMQ; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package net.timewalker.ffmq4.local;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.jms.Connection;
import javax.jms.InvalidDestinationException;
import javax.jms.JMSException;
import javax.jms.QueueConnection;
import javax.jms.TopicConnection;

import net.timewalker.ffmq4.FFMQException;
import net.timewalker.ffmq4.FFMQSecurityException;
import net.timewalker.ffmq4.local.connection.ClientIDRegistry;
import net.timewalker.ffmq4.local.connection.LocalConnection;
import net.timewalker.ffmq4.local.connection.LocalQueueConnection;
import net.timewalker.ffmq4.local.connection.LocalTopicConnection;
import net.timewalker.ffmq4.local.destination.LocalQueue;
import net.timewalker.ffmq4.local.destination.LocalTopic;
import net.timewalker.ffmq4.local.destination.subscription.DurableSubscriptionManager;
import net.timewalker.ffmq4.management.DestinationDefinitionProvider;
import net.timewalker.ffmq4.management.DestinationTemplateProvider;
import net.timewalker.ffmq4.management.FFMQEngineSetup;
import net.timewalker.ffmq4.management.TemplateMappingProvider;
import net.timewalker.ffmq4.management.destination.definition.QueueDefinition;
import net.timewalker.ffmq4.management.destination.definition.TopicDefinition;
import net.timewalker.ffmq4.management.destination.template.QueueTemplate;
import net.timewalker.ffmq4.management.destination.template.TopicTemplate;
import net.timewalker.ffmq4.security.SecurityConnectorProvider;
import net.timewalker.ffmq4.security.SecurityContext;
import net.timewalker.ffmq4.storage.data.DataStoreException;
import net.timewalker.ffmq4.storage.data.impl.BlockBasedDataStoreTools;
import net.timewalker.ffmq4.utils.ErrorTools;
import net.timewalker.ffmq4.utils.Settings;
import net.timewalker.ffmq4.utils.StringTools;
import net.timewalker.ffmq4.utils.async.AsyncTaskManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <p>
 *    Implementation of the core FFMQ engine.
 * </p>
 * <p>
 *    Typically created by an FFMQServer instance, but can also be created manually
 *    to be embedded directly in the using application JVM. 
 * </p>
 */
public final class FFMQEngine implements FFMQEngineMBean {
    private static final Log log = LogFactory.getLog(FFMQEngine.class);

    private static Map<String, FFMQEngine> deployedEngines = new Hashtable<>();

    /**
     * Get a deployed engine instance by name
     */
    public static FFMQEngine getDeployedInstance(String name) throws JMSException {
        FFMQEngine engine = deployedEngines.get(name);
        if (engine == null)
            throw new FFMQException("No deployed engine named " + name, "UNKNOWN_ENGINE");
        return engine;
    }

    //--------------------------------------------------------------------

    private String name;
    private FFMQEngineListener listener;
    private Map<String, LocalQueue> queueMap = new Hashtable<>();
    private Map<String, LocalTopic> topicMap = new Hashtable<>();
    private boolean deployed = false;
    private boolean securityEnabled;
    private FFMQEngineSetup setup;
    private DestinationDefinitionProvider destinationDefinitionProvider;
    private DestinationTemplateProvider destinationTemplateProvider;
    private TemplateMappingProvider templateMappingProvider;
    private DurableSubscriptionManager durableSubscriptionManager;

    // Thread pools
    private AsyncTaskManager notificationAsyncTaskManager;
    private AsyncTaskManager deliveryAsyncTaskManager;
    private AsyncTaskManager diskIOAsyncTaskManager;

    /**
     * Constructor
     * @throws FFMQException on configuration error
     */
    public FFMQEngine(String name, Settings engineSettings) throws FFMQException {
        this(name, engineSettings, null);
    }

    /**
     * Constructor
     * @throws FFMQException on configuration error
     */
    public FFMQEngine(String name, Settings engineSettings, FFMQEngineListener listener) throws FFMQException {
        this.name = name;
        this.listener = listener;
        this.setup = new FFMQEngineSetup(engineSettings);
        init();
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq4.local.LocalEngineMBean#getName()
     */
    @Override
    public String getName() {
        return name;
    }

    /**
     * Check that the engine is running
     */
    protected void checkDeployed() throws JMSException {
        if (!deployed)
            throw new FFMQException("Engine is stopped.", "ENGINE_STOPPED");
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq4.local.LocalEngineMBean#isDeployed()
     */
    @Override
    public boolean isDeployed() {
        return deployed;
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq4.local.FFMQEngineMBean#isSecurityEnabled()
     */
    @Override
    public boolean isSecurityEnabled() {
        return securityEnabled;
    }

    private void init() {
        this.destinationDefinitionProvider = new DestinationDefinitionProvider(setup);
        this.destinationTemplateProvider = new DestinationTemplateProvider(setup);
        this.templateMappingProvider = new TemplateMappingProvider(setup);
        this.securityEnabled = setup.isSecurityEnabled();
        this.durableSubscriptionManager = new DurableSubscriptionManager();
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq4.local.LocalEngineMBean#deploy()
     */
    public void deploy() throws JMSException {
        try {
            synchronized (deployedEngines) {
                if (deployed)
                    throw new FFMQException("Local engine is already deployed.", "ENGINE_ALREADY_DEPLOYED");

                log.info("Deploying local engine '" + name + "'");
                this.destinationDefinitionProvider.loadExistingDefinitions();
                this.destinationTemplateProvider.loadExistingTemplates();
                this.templateMappingProvider.loadMappings();

                // AsyncTaskManager - Notification
                this.notificationAsyncTaskManager = new AsyncTaskManager("AsyncTaskManager-notification-" + name,
                        setup.getNotificationAsyncTaskManagerThreadPoolMinSize(),
                        setup.getNotificationAsyncTaskManagerThreadPoolMaxIdle(),
                        setup.getNotificationAsyncTaskManagerThreadPoolMaxSize());

                // AsyncTaskManager - Delivery
                this.deliveryAsyncTaskManager = new AsyncTaskManager("AsyncTaskManager-delivery-" + name,
                        setup.getDeliveryAsyncTaskManagerThreadPoolMinSize(),
                        setup.getDeliveryAsyncTaskManagerThreadPoolMaxIdle(),
                        setup.getDeliveryAsyncTaskManagerThreadPoolMaxSize());

                // AsyncTaskManager - Disk I/O
                this.diskIOAsyncTaskManager = new AsyncTaskManager("AsyncTaskManager-diskIO-" + name,
                        setup.getDiskIOAsyncTaskManagerThreadPoolMinSize(),
                        setup.getDiskIOAsyncTaskManagerThreadPoolMaxIdle(),
                        setup.getDiskIOAsyncTaskManagerThreadPoolMaxSize());

                // Delete old temporary destinations
                deleteTemporaryDestinations();

                // Deploy existing destinations
                if (setup.doDeployQueuesOnStartup())
                    deployExistingQueues();
                if (setup.doDeployTopicsOnStartup())
                    deployExistingTopics();

                deployedEngines.put(name, this);
                deployed = true;
                log.info("Engine deployed (vm://" + name + ")");
            }

            if (listener != null)
                listener.engineDeployed();
        } catch (JMSException e) {
            log.error("Cannot deploy engine : " + e.getMessage());
            throw e;
        }
    }

    /**
     * Get the destination template provider associated to this engine
     * @return the destination template provider associated to this engine
     */
    public DestinationTemplateProvider getDestinationTemplateProvider() {
        return destinationTemplateProvider;
    }

    /**
     * Get the template mapping provider associated to this engine
     * @return the template mapping provider associated to this engine
     */
    public TemplateMappingProvider getTemplateMappingProvider() {
        return templateMappingProvider;
    }

    private void deleteTemporaryDestinations() throws JMSException {
        String[] queueNames = destinationDefinitionProvider.getAllQueueNames();
        for (int i = 0; i < queueNames.length; i++) {
            QueueDefinition queueDef = destinationDefinitionProvider.getQueueDefinition(queueNames[i]);
            if (queueDef.isTemporary()) {
                log.info("Deleting old temporary queue : " + queueNames[i]);
                deleteQueue(queueNames[i], true);
            }
        }
        String[] topicNames = destinationDefinitionProvider.getAllTopicNames();
        for (int i = 0; i < topicNames.length; i++) {
            TopicDefinition topicDef = destinationDefinitionProvider.getTopicDefinition(topicNames[i]);
            if (topicDef.isTemporary()) {
                log.info("Deleting old temporary topic : " + topicNames[i]);
                deleteTopic(topicNames[i]);
            }
        }
    }

    private void deployExistingQueues() {
        log.info("Deploying existing queues");
        String[] queueNames = destinationDefinitionProvider.getAllQueueNames();
        for (int i = 0; i < queueNames.length; i++) {
            try {
                getLocalQueue(queueNames[i]);
            } catch (JMSException e) {
                ErrorTools.log(e, log);
            }
        }
    }

    private void deployExistingTopics() {
        log.info("Deploying existing topics");
        String[] topicNames = destinationDefinitionProvider.getAllTopicNames();
        for (int i = 0; i < topicNames.length; i++) {
            try {
                getLocalTopic(topicNames[i]);
            } catch (JMSException e) {
                ErrorTools.log(e, log);
            }
        }
    }

    /**
     * Get the engine setup
     */
    public FFMQEngineSetup getSetup() {
        return setup;
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq4.local.LocalEngineMBean#undeploy()
     */
    public void undeploy() {
        synchronized (deployedEngines) {
            if (!deployed)
                return;

            // Undeploy engine
            log.info("Undeploying local engine '" + name + "'");
            durableSubscriptionManager = null;

            // Stop async task manager - notification
            if (notificationAsyncTaskManager != null) {
                notificationAsyncTaskManager.close();
                notificationAsyncTaskManager = null;
            }

            // Stop async task manager - delivery
            if (deliveryAsyncTaskManager != null) {
                deliveryAsyncTaskManager.close();
                deliveryAsyncTaskManager = null;
            }

            // Undeploy queues
            synchronized (queueMap) {
                List<LocalQueue> queues = new ArrayList<>();
                queues.addAll(queueMap.values());
                for (int i = 0; i < queues.size(); i++) {
                    LocalQueue localQueue = queues.get(i);
                    try {
                        undeployQueue(localQueue);
                    } catch (JMSException e) {
                        ErrorTools.log(e, log);
                    }
                }
            }

            // Close topics
            synchronized (topicMap) {
                List<LocalTopic> topics = new ArrayList<>();
                topics.addAll(topicMap.values());
                for (int i = 0; i < topics.size(); i++) {
                    LocalTopic localTopic = topics.get(i);
                    try {
                        undeployTopic(localTopic);
                    } catch (JMSException e) {
                        ErrorTools.log(e, log);
                    }
                }
            }

            // Stop async task manager - disk I/O
            if (diskIOAsyncTaskManager != null) {
                diskIOAsyncTaskManager.close();
                diskIOAsyncTaskManager = null;
            }

            // Clear templates
            destinationTemplateProvider.clear();

            deployedEngines.remove(name);
            deployed = false;
        }

        if (listener != null)
            listener.engineUndeployed();
    }

    /**
     * Open a new connection
     */
    public Connection openConnection(String userName, String password, String clientID) throws JMSException {
        checkDeployed();
        if (clientID != null)
            ClientIDRegistry.getInstance().register(clientID);
        return new LocalConnection(this, getSecurityContext(userName, password), clientID);
    }

    /**
     * Open a new queue connection
     */
    public QueueConnection openQueueConnection(String userName, String password, String clientID)
            throws JMSException {
        checkDeployed();
        if (clientID != null)
            ClientIDRegistry.getInstance().register(clientID);
        return new LocalQueueConnection(this, getSecurityContext(userName, password), clientID);
    }

    /**
     * Open a new topic connection
     */
    public TopicConnection openTopicConnection(String userName, String password, String clientID)
            throws JMSException {
        checkDeployed();
        if (clientID != null)
            ClientIDRegistry.getInstance().register(clientID);
        return new LocalTopicConnection(this, getSecurityContext(userName, password), clientID);
    }

    private SecurityContext getSecurityContext(String userName, String password) throws JMSException {
        if (!securityEnabled)
            return null;

        if (userName == null || password == null)
            throw new FFMQSecurityException("Missing security credentials", "MISSING_CREDENTIALS");

        return SecurityConnectorProvider.getConnector(setup).getContext(userName, password);
    }

    /**
     * Deploy a new temporary queue on this engine
     */
    public LocalQueue createTemporaryQueue(String queueName) throws JMSException {
        String templateName = templateMappingProvider.getTemplateNameForQueue(queueName);
        if (StringTools.isEmpty(templateName))
            throw new FFMQException("No template matching queue : " + queueName, "MISSING_TEMPLATE_MAPPING");

        QueueTemplate queueTemplate = destinationTemplateProvider.getQueueTemplate(templateName);
        if (queueTemplate == null)
            throw new FFMQException("Queue template does not exist : " + templateName, "MISSING_TEMPLATE");

        QueueDefinition tempDef = queueTemplate.createQueueDefinition(queueName, true);
        return createQueue(tempDef);
    }

    /**
     * Deploy a new queue on this engine
     */
    public LocalQueue createQueue(QueueDefinition queueDef) throws JMSException {
        queueDef.check();

        if (queueDef.hasPersistentStore() && setup.getDestinationDefinitionsDir() == null)
            throw new FFMQException("Cannot create a persistent queue if destinations folder is not set.",
                    "INVALID_CONFIGURATION");

        synchronized (queueMap) {
            if (destinationDefinitionProvider.getQueueDefinition(queueDef.getName()) != null)
                throw new FFMQException("Queue definition already exists : " + queueDef.getName(),
                        "QUEUE_ALREADY_EXISTS");

            // Inject the new definition
            destinationDefinitionProvider.addQueueDefinition(queueDef);

            // If it's not a volatile queue, create the data files
            if (queueDef.hasPersistentStore()) {
                log.debug("Creating local store for queue : " + queueDef.getName());
                try {
                    BlockBasedDataStoreTools.create(queueDef.getName(), queueDef.getDataFolder(),
                            queueDef.getInitialBlockCount(), queueDef.getBlockSize(), !queueDef.isTemporary());
                } catch (DataStoreException e) {
                    // Remove the queue definition
                    destinationDefinitionProvider.removeQueueDefinition(queueDef);
                    throw e;
                }
            }

            return getLocalQueue(queueDef.getName());
        }
    }

    /**
     * Deploy a new temporary topic on this engine
     */
    public LocalTopic createTemporaryTopic(String topicName) throws JMSException {
        String templateName = templateMappingProvider.getTemplateNameForTopic(topicName);
        if (StringTools.isEmpty(templateName))
            throw new FFMQException("No template matching topic : " + topicName, "MISSING_TEMPLATE_MAPPING");

        TopicTemplate topicTemplate = destinationTemplateProvider.getTopicTemplate(templateName);
        if (topicTemplate == null)
            throw new FFMQException("Topic template does not exist : " + templateName, "MISSING_TEMPLATE");

        TopicDefinition tempDef = topicTemplate.createTopicDefinition(topicName, true);
        return createTopic(tempDef);
    }

    /**
     * Create a new topic
     */
    public LocalTopic createTopic(TopicDefinition topicDef) throws JMSException {
        topicDef.check();

        synchronized (topicMap) {
            if (destinationDefinitionProvider.getTopicDefinition(topicDef.getName()) != null)
                throw new FFMQException("Topic definition already exists : " + topicDef.getName(),
                        "TOPIC_ALREADY_EXISTS");

            destinationDefinitionProvider.addTopicDefinition(topicDef);

            return getLocalTopic(topicDef.getName());
        }
    }

    /**
     * Undeploy a queue
     */
    public void deleteQueue(String queueName) throws JMSException {
        deleteQueue(queueName, false);
    }

    /**
     * Undeploy a queue
     */
    public void deleteQueue(String queueName, boolean force) throws JMSException {
        synchronized (queueMap) {
            LocalQueue queue = queueMap.get(queueName);
            if (queue != null) {
                undeployQueue(queue);
                log.debug("Undeployed local queue : " + queueName);
            }

            QueueDefinition queueDef = destinationDefinitionProvider.getQueueDefinition(queueName);
            if (queueDef != null) {
                destinationDefinitionProvider.removeQueueDefinition(queueDef);

                if (queueDef.hasPersistentStore())
                    BlockBasedDataStoreTools.delete(queueDef.getName(), queueDef.getDataFolder(), force);
            }
        }
    }

    /**
     * Undeploy a topic
     */
    public void deleteTopic(String topicName) throws JMSException {
        synchronized (topicMap) {
            LocalTopic topic = topicMap.remove(topicName);
            if (topic != null) {
                undeployTopic(topic);
                log.debug("Undeployed local topic : " + topicName);
            }

            TopicDefinition topicDef = destinationDefinitionProvider.getTopicDefinition(topicName);
            if (topicDef != null)
                destinationDefinitionProvider.removeTopicDefinition(topicName);
        }
    }

    /**
     * Get a local queue by name
     */
    public LocalQueue getLocalQueue(String queueName) throws JMSException {
        synchronized (queueMap) {
            LocalQueue queue = queueMap.get(queueName);
            if (queue == null)
                return loadOrAutoCreateQueue(queueName);

            return queue;
        }
    }

    /**
     * Test if a local queue exists by name
     */
    public boolean localQueueExists(String queueName) throws JMSException {
        synchronized (queueMap) {
            LocalQueue queue = queueMap.get(queueName);
            if (queue != null)
                return true;

            // Check if a definition exists
            if (destinationDefinitionProvider.getQueueDefinition(queueName) != null)
                return true;

            return false;
        }
    }

    private void deployQueue(LocalQueue queue) {
        queueMap.put(queue.getName(), queue);
        if (listener != null)
            listener.queueDeployed(queue);
    }

    private void deployTopic(LocalTopic topic) {
        topicMap.put(topic.getName(), topic);
        if (listener != null)
            listener.topicDeployed(topic);
    }

    private void undeployQueue(LocalQueue queue) throws JMSException {
        queue.close();
        queueMap.remove(queue.getName());

        // Destroy temporary queues automatically
        if (queue.getDefinition().isTemporary())
            destinationDefinitionProvider.removeQueueDefinition(queue.getDefinition());

        if (listener != null)
            listener.queueUndeployed(queue);
    }

    private void undeployTopic(LocalTopic topic) throws JMSException {
        topic.close();
        topicMap.remove(topic.getName());

        if (listener != null)
            listener.topicUndeployed(topic);
    }

    private LocalQueue loadOrAutoCreateQueue(String queueName) throws JMSException {
        QueueDefinition queueDef = destinationDefinitionProvider.getQueueDefinition(queueName);
        if (queueDef != null) {
            LocalQueue queue = new LocalQueue(this, queueDef);
            deployQueue(queue);
            return queue;
        }

        // Queue auto-creation
        if (setup.doAutoCreateQueues()) {
            // Look for matching template
            String templateName = templateMappingProvider.getTemplateNameForQueue(queueName);
            if (templateName != null) {
                QueueTemplate queueTemplate = destinationTemplateProvider.getQueueTemplate(templateName);
                if (queueTemplate != null)
                    return createQueue(queueTemplate.createQueueDefinition(queueName, false));
            }
        }

        throw new FFMQException("Queue does not exist : " + queueName, "QUEUE_DOES_NOT_EXIST");
    }

    /**
     * Get a local topic by name
     */
    public LocalTopic getLocalTopic(String topicName) throws JMSException {
        synchronized (topicMap) {
            LocalTopic topic = topicMap.get(topicName);
            if (topic == null)
                return loadOrAutoCreateTopic(topicName);

            return topic;
        }
    }

    /**
     * Test if a local topic exists by name
     */
    public boolean localTopicExists(String topicName) throws JMSException {
        synchronized (topicMap) {
            LocalTopic topic = topicMap.get(topicName);
            if (topic != null)
                return true;

            // Check if a definition exists
            if (destinationDefinitionProvider.getTopicDefinition(topicName) != null)
                return true;

            return false;
        }
    }

    private LocalTopic loadOrAutoCreateTopic(String topicName) throws JMSException {
        TopicDefinition topicDef = destinationDefinitionProvider.getTopicDefinition(topicName);
        if (topicDef != null) {
            LocalTopic topic = new LocalTopic(topicDef);
            deployTopic(topic);
            return topic;
        }

        // Topic auto-creation
        if (setup.doAutoCreateTopics()) {
            String templateName = templateMappingProvider.getTemplateNameForTopic(topicName);
            if (templateName != null) {
                TopicTemplate topicTemplate = destinationTemplateProvider.getTopicTemplate(templateName);
                if (topicTemplate != null)
                    return createTopic(topicTemplate.createTopicDefinition(topicName, false));
            }
        }

        throw new FFMQException("Topic does not exist : " + topicName, "TOPIC_DOES_NOT_EXIST");
    }

    public void subscribe(String clientID, String subscriptionName) throws JMSException {
        if (durableSubscriptionManager == null)
            throw new FFMQException("Engine is stopped.", "ENGINE_STOPPED");

        if (durableSubscriptionManager.register(clientID, subscriptionName))
            log.debug("Storing a new durable subscription : " + clientID + "-" + subscriptionName);
        else
            log.debug("Subscription already exist : " + clientID + "-" + subscriptionName);
    }

    /**
     * Unsubscribe a durable subscriber from all related topics
     */
    public void unsubscribe(String clientID, String subscriptionName) throws JMSException {
        if (durableSubscriptionManager == null)
            throw new FFMQException("Engine is stopped.", "ENGINE_STOPPED");

        // Check that the registration is valid
        if (!durableSubscriptionManager.isRegistered(clientID, subscriptionName))
            throw new InvalidDestinationException(
                    "Invalid subscription : " + subscriptionName + " for client " + clientID); // [JMS spec]

        // Try to remove all remanent subscriptions first
        synchronized (topicMap) {
            Iterator<LocalTopic> topics = topicMap.values().iterator();
            while (topics.hasNext()) {
                LocalTopic topic = topics.next();
                topic.unsubscribe(clientID, subscriptionName);
            }
        }

        // Then delete subscription related queues
        String subscriberID = clientID + "-" + subscriptionName;
        synchronized (queueMap) {
            List<String> queuesToDelete = new ArrayList<>();
            Iterator<String> queueNames = queueMap.keySet().iterator();
            while (queueNames.hasNext()) {
                String queueName = queueNames.next();
                if (queueName.endsWith(subscriberID))
                    queuesToDelete.add(queueName);
            }

            // Delete matching queues
            for (int i = 0; i < queuesToDelete.size(); i++)
                deleteQueue(queuesToDelete.get(i));
        }

        // Clean-up the subscription itself
        if (!durableSubscriptionManager.unregister(clientID, subscriptionName))
            log.error("Unknown durable subscription : " + clientID + "-" + subscriptionName);
    }

    /**
     * Get the engine async. notification task manager
    * @return the engine async. notification task manager
    */
    public AsyncTaskManager getNotificationAsyncTaskManager() throws JMSException {
        if (notificationAsyncTaskManager == null)
            throw new FFMQException("Engine is stopped.", "ENGINE_STOPPED");
        return notificationAsyncTaskManager;
    }

    /**
     * Get the engine async. delivery task manager
    * @return the engine async. delivery task manager
    */
    public AsyncTaskManager getDeliveryAsyncTaskManager() throws JMSException {
        if (deliveryAsyncTaskManager == null)
            throw new FFMQException("Engine is stopped.", "ENGINE_STOPPED");
        return deliveryAsyncTaskManager;
    }

    /**
      * Get the engine async. disk I/O task manager
     * @return the engine async. disk I/O task manager
     */
    public AsyncTaskManager getDiskIOAsyncTaskManager() throws JMSException {
        if (diskIOAsyncTaskManager == null)
            throw new FFMQException("Engine is stopped.", "ENGINE_STOPPED");
        return diskIOAsyncTaskManager;
    }

    /**
     * @return the destinationDefinitionProvider
     */
    public DestinationDefinitionProvider getDestinationDefinitionProvider() {
        return destinationDefinitionProvider;
    }

    /* (non-Javadoc)
     * @see net.timewalker.ffmq4.local.FFMQEngineMBean#clearAllStatistics()
     */
    @Override
    public void resetAllStatistics() {
        synchronized (queueMap) {
            Iterator<LocalQueue> queues = queueMap.values().iterator();
            while (queues.hasNext()) {
                LocalQueue queue = queues.next();
                queue.resetStats();
            }
        }
        synchronized (topicMap) {
            Iterator<LocalTopic> topics = topicMap.values().iterator();
            while (topics.hasNext()) {
                LocalTopic topic = topics.next();
                topic.resetStats();
            }
        }
    }
}