net.timewalker.ffmq4.admin.RemoteAdministrationThread.java Source code

Java tutorial

Introduction

Here is the source code for net.timewalker.ffmq4.admin.RemoteAdministrationThread.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.admin;

import java.util.Enumeration;

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;

import net.timewalker.ffmq4.FFMQAdminConstants;
import net.timewalker.ffmq4.FFMQConstants;
import net.timewalker.ffmq4.FFMQException;
import net.timewalker.ffmq4.FFMQServer;
import net.timewalker.ffmq4.local.FFMQEngine;
import net.timewalker.ffmq4.local.connection.LocalQueueConnection;
import net.timewalker.ffmq4.local.destination.LocalQueue;
import net.timewalker.ffmq4.management.destination.definition.QueueDefinition;
import net.timewalker.ffmq4.management.destination.definition.TopicDefinition;
import net.timewalker.ffmq4.utils.ErrorTools;
import net.timewalker.ffmq4.utils.Settings;
import net.timewalker.ffmq4.utils.StringTools;
import net.timewalker.ffmq4.utils.concurrent.SynchronizableThread;

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

/**
 * AdministrationThread
 */
public final class RemoteAdministrationThread extends SynchronizableThread {
    private static final Log log = LogFactory.getLog(RemoteAdministrationThread.class);

    protected FFMQServer server;
    private FFMQEngine engine;
    private QueueConnection conn = null;
    private QueueSession session = null;
    private QueueSender sender = null;
    private QueueReceiver receiver = null;
    private boolean stopRequired = false;

    /**
     * Constructor
     */
    public RemoteAdministrationThread(FFMQServer server, FFMQEngine engine) {
        super("FFMQ-RemoteAdminThread");
        this.server = server;
        this.engine = engine;
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq4.utils.concurrent.SynchronizableThread#run()
     */
    @Override
    public void run() {
        log.info("Starting remote administration thread ...");

        try {
            LocalQueue inputQueue = engine.getLocalQueue(FFMQConstants.ADM_REQUEST_QUEUE);
            LocalQueue outputQueue = engine.getLocalQueue(FFMQConstants.ADM_REPLY_QUEUE);

            conn = new LocalQueueConnection(engine, null, null);
            session = conn.createQueueSession(true, Session.SESSION_TRANSACTED);
            receiver = session.createReceiver(inputQueue);
            sender = session.createSender(outputQueue);

            conn.start();

            // Flush input queue on startup
            inputQueue.purge(null);
            outputQueue.purge(null);

            // Enter listening loop
            notifyStartup();
            while (!stopRequired) {
                Message message = receiver.receive();
                if (message == null)
                    break; // Interrupted
                log.debug("Received message " + message);

                try {
                    // Process the command
                    String errorMsg = process(message);

                    // Build response message
                    Message response = session.createMessage();
                    response.setJMSCorrelationID(message.getJMSMessageID());
                    if (errorMsg != null)
                        response.setStringProperty(FFMQAdminConstants.ADM_HEADER_ERRMSG, errorMsg);

                    sender.send(response, DeliveryMode.NON_PERSISTENT, Message.DEFAULT_PRIORITY,
                            Message.DEFAULT_TIME_TO_LIVE);
                } catch (JMSException e) {
                    log.error("Cannot process admin command", e);
                } finally {
                    session.commit();
                }
            }

            log.debug("Remote administration thread has stopped");
        } catch (Throwable e) {
            log.fatal("Administration thread failed", e);
            notifyStartup();
        } finally {
            try {
                if (sender != null)
                    sender.close();
            } catch (JMSException e) {
                ErrorTools.log(e, log);
            }

            try {
                if (receiver != null)
                    receiver.close();
            } catch (JMSException e) {
                ErrorTools.log(e, log);
            }

            try {
                if (session != null)
                    session.close();
            } catch (JMSException e) {
                ErrorTools.log(e, log);
            }

            try {
                if (conn != null)
                    conn.close();
            } catch (JMSException e) {
                ErrorTools.log(e, log);
            }
        }
    }

    private String process(Message msg) {
        try {
            String command = msg.getStringProperty(FFMQAdminConstants.ADM_HEADER_COMMAND);
            if (StringTools.isEmpty(command))
                return "Administration command not set in message header";

            // Dispatch
            if (command.equals(FFMQAdminConstants.ADM_COMMAND_CREATE_QUEUE))
                return processCreateQueue(msg);

            if (command.equals(FFMQAdminConstants.ADM_COMMAND_CREATE_TOPIC))
                return processCreateTopic(msg);

            if (command.equals(FFMQAdminConstants.ADM_COMMAND_DELETE_QUEUE))
                return processDeleteQueue(msg);

            if (command.equals(FFMQAdminConstants.ADM_COMMAND_DELETE_TOPIC))
                return processDeleteTopic(msg);

            if (command.equals(FFMQAdminConstants.ADM_COMMAND_PURGE_QUEUE))
                return processPurgeQueue(msg);

            if (command.equals(FFMQAdminConstants.ADM_COMMAND_SHUTDOWN))
                return processShutdown();

            log.error("Invalid administration command : " + command);
            return "Invalid administration command : " + command;
        } catch (JMSException e) {
            ErrorTools.log(e, log);
            return "Error processing administration command : " + e.getMessage();
        } catch (Exception e) {
            ErrorTools.log(new FFMQException("Cannot process admin message", "INVALID_ADMIN_MESSAGE", e), log);
            return "Error processing administration command : " + e.getMessage();
        }
    }

    private Settings createSettings(Message msg) throws JMSException {
        // Fill settings from message headers
        Settings queueSettings = new Settings();
        Enumeration<?> headers = msg.getPropertyNames();
        while (headers.hasMoreElements()) {
            String propName = (String) headers.nextElement();
            if (propName.startsWith(FFMQAdminConstants.ADM_HEADER_PREFIX))
                continue;

            String propValue = msg.getStringProperty(propName);
            queueSettings.setStringProperty(propName, propValue);
        }
        return queueSettings;
    }

    private String processCreateQueue(Message msg) throws JMSException {
        Settings queueSettings = createSettings(msg);
        QueueDefinition queueDef = new QueueDefinition(queueSettings);

        log.debug("Creating queue : " + queueDef);
        engine.createQueue(queueDef);

        // Success
        return null;
    }

    private String processCreateTopic(Message msg) throws JMSException {
        Settings topicSettings = createSettings(msg);
        TopicDefinition topicDef = new TopicDefinition(topicSettings);

        log.debug("Creating topic : " + topicDef);
        engine.createTopic(topicDef);

        // Success
        return null;
    }

    private String processDeleteQueue(Message msg) throws JMSException {
        String destName = msg.getStringProperty("name");
        if (StringTools.isEmpty(destName))
            return "Destination name not specified";

        if (!engine.localQueueExists(destName))
            return "Queue " + destName + " does not exist";

        engine.deleteQueue(destName);

        return null;
    }

    private String processDeleteTopic(Message msg) throws JMSException {
        String destName = msg.getStringProperty("name");
        if (StringTools.isEmpty(destName))
            return "Destination name not specified";

        if (!engine.localTopicExists(destName))
            return "Topic " + destName + " does not exist";

        engine.deleteTopic(destName);

        return null;
    }

    private String processPurgeQueue(Message msg) throws JMSException {
        String destName = msg.getStringProperty("name");
        if (StringTools.isEmpty(destName))
            return "Destination name not specified";

        if (!engine.localQueueExists(destName))
            return "Queue " + destName + " does not exist";

        LocalQueue queue = engine.getLocalQueue(destName);
        queue.purge(null);

        return null;
    }

    private String processShutdown() {
        // Shutdown the server
        if (server.isInRunnableMode())
            server.pleaseStop();
        else {
            // Run the shutdown sequence in a parallel thread to avoid deadlocks
            new Thread() {
                @Override
                public void run() {
                    server.shutdown();
                }
            }.start();
        }

        return null;
    }

    /**
     * Ask the thread to stop
     */
    public void pleaseStop() {
        if (stopRequired)
            return;

        stopRequired = true;
        try {
            if (receiver != null)
                receiver.close();
        } catch (JMSException e) {
            ErrorTools.log(e, log);
        }
    }
}