org.objectrepository.MessageConsumerDaemon.java Source code

Java tutorial

Introduction

Here is the source code for org.objectrepository.MessageConsumerDaemon.java

Source

/*
 * Copyright 2010 International Institute for Social History, The Netherlands.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.objectrepository;

import org.apache.camel.ConsumerTemplate;
import org.apache.camel.ProducerTemplate;
import org.apache.log4j.Logger;
import org.objectrepository.services.MediatorQueue;
import org.objectrepository.services.MediatorTopic;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.RejectedExecutionHandler;

public class MessageConsumerDaemon extends Thread implements Runnable {

    private static MessageConsumerDaemon instance;
    private boolean keepRunning = true;
    private GenericXmlApplicationContext context;
    private long timer;
    private long timerInterval = 10000;
    private long heartbeatInterval = 10000;
    private List<Queue> taskExecutors;
    private String identifier;
    final private static Logger log = Logger.getLogger(MessageConsumerDaemon.class);
    private boolean pause = false;
    private boolean stop = false;

    private MessageConsumerDaemon() {
        timer = System.currentTimeMillis() + timerInterval;
    }

    public void run() {

        init();
        while (keepRunning) {
            if (isStop()) {
                for (Queue queue : taskExecutors) {
                    keepRunning = keepRunning && (queue.getActiveCount() != 0);
                }
            } else {
                for (Queue queue : taskExecutors) {
                    if (isPause() && queue.isTopic() || !isPause()) {
                        if (queue.getActiveCount() < queue.getMaxPoolSize()) {
                            log.debug(queue.getQueueName() + " has activeCount " + queue.getActiveCount()
                                    + " / maxPoolSize " + queue.getMaxPoolSize());
                            queue.execute(mediatorInstance(queue));
                        }
                    }
                }
            }
            heartbeat();
        }
        context.close();
    }

    public void init() {

        log.info("Startup service...");
        GenericXmlApplicationContext context = new GenericXmlApplicationContext();
        context.setValidating(false);
        context.load("/META-INF/spring/application-context.xml", "META-INF/spring/dispatcher-servlet.xml");
        context.refresh();
        setContext(context);
        context.registerShutdownHook();

        final RejectedExecutionHandler rejectedExecutionHandler = context.getBean(RejectedExecutionHandler.class);
        for (Queue taskExecutor : taskExecutors) {
            taskExecutor.setRejectedExecutionHandler(rejectedExecutionHandler);
            taskExecutor.initialize();
            log.info("Initialized " + taskExecutor.getQueueName());
        }
    }

    private Runnable mediatorInstance(Queue queue) {

        if (queue.isTopic()) {
            log.info("Adding topic consumer for " + queue.getQueueName());
            return new MediatorTopic(this, context.getBean(ConsumerTemplate.class),
                    "activemq:topic:" + queue.getQueueName());
        } else {
            log.info("Adding queue consumer for " + queue.getQueueName());
            return new MediatorQueue(context.getBean(MongoTemplate.class), context.getBean(ConsumerTemplate.class),
                    context.getBean(ProducerTemplate.class), "activemq:" + queue.getQueueName(),
                    queue.getShellScript(), heartbeatInterval);
        }
    }

    /**
     * heartbeat
     * <p/>
     * Keeps the overall environment from overworking by pausing every ten seconds or so.
     */
    private void heartbeat() {

        long currentTime = System.currentTimeMillis();
        if (timer - currentTime < 0) {
            timer = currentTime + timerInterval;
            if (isPause()) {
                log.info("We are in pause mode.");
            } else {
                log.info("Actively listening to queues.");
            }
        }

        try {
            sleep(1000);
        } catch (InterruptedException e) {
            interrupt();
        } catch (Throwable t) {
            log.error("Cannot put thread to sleep..."); // Can we ignore this ?
        }
    }

    /**
     * setTaskExecutors
     * <p/>
     * Sets the queues.
     *
     * @param taskExecutors
     */
    public void setTaskExecutors(List<Queue> taskExecutors) {
        this.taskExecutors = taskExecutors;
    }

    /**
     * Method clone should not be allowed for a singleton.
     *
     * @return The cloned object that never will be returned
     * @throws CloneNotSupportedException
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public static synchronized MessageConsumerDaemon getInstance(List<Queue> queues, String identifier,
            long heartbeatInterval) {

        if (instance == null) {
            instance = new MessageConsumerDaemon();
            instance.setTaskExecutors(queues);
            instance.setIdentifier(identifier);
            instance.setDaemon(true);
            instance.setHeartbeatInterval(heartbeatInterval);
        }
        return instance;
    }

    /**
     * main
     * <p/>
     * Accepts one folder as argument:  -messageQueues
     * That folder ought to contain one or more folders ( or symbolic links ) to the files
     * The folder has the format: [foldername] or [foldername].[maxTasks]
     * MaxTasks is to indicate the total number of jobs being able to run.
     *
     * long
     *
     * @param argv
     */
    public static void main(String[] argv) {

        if (instance == null) {
            final Properties properties = new Properties();

            if (argv.length > 0) {
                for (int i = 0; i < argv.length; i += 2) {
                    try {
                        properties.put(argv[i], argv[i + 1]);
                    } catch (ArrayIndexOutOfBoundsException arr) {
                        System.out.println("Missing value after parameter " + argv[i]);
                        System.exit(-1);
                    }
                }
            } else {
                log.fatal("Usage: pmq-agent.jar -messageQueues [queues] -heartbeatInterval [interval in ms]\n"
                        + "The queues is a folder that contains symbolic links to the startup scripts.");
                System.exit(-1);
            }

            if (log.isInfoEnabled()) {
                log.info("Arguments set: ");
                for (String key : properties.stringPropertyNames()) {
                    log.info("'" + key + "'='" + properties.getProperty(key) + "'");
                }
            }

            if (!properties.containsKey("-messageQueues")) {
                log.fatal("Expected case sensitive parameter: -messageQueues");
                System.exit(-1);
            }

            final File messageQueues = new File((String) properties.get("-messageQueues"));
            if (!messageQueues.exists()) {
                log.fatal("Cannot find folder for messageQueues: " + messageQueues.getAbsolutePath());
                System.exit(-1);
            }

            if (messageQueues.isFile()) {
                log.fatal(
                        "-messageQueues should point to a folder, not a file: " + messageQueues.getAbsolutePath());
                System.exit(-1);
            }

            long heartbeatInterval = 600000;
            if (properties.containsKey("-heartbeatInterval")) {
                heartbeatInterval = Long.parseLong((String) properties.get("heartbeatInterval"));
            }

            String identifier = null;
            if (properties.containsKey("-id")) {
                identifier = (String) properties.get("-id");
            } else if (properties.containsKey("-identifier")) {
                identifier = (String) properties.get("-identifier");
            }

            final File[] files = messageQueues.listFiles();
            final String[] scriptNames = (properties.containsKey("-startup"))
                    ? new String[] { properties.getProperty("-startup") }
                    : new String[] { "/startup.sh", "\\startup.bat" };
            final List<Queue> queues = new ArrayList<Queue>();
            for (File file : files) {
                final String name = file.getName();
                final String[] split = name.split("\\.", 2);
                final String queueName = split[0];
                for (String scriptName : scriptNames) {
                    final String shellScript = file.getAbsolutePath() + scriptName;
                    final int maxTask = (split.length == 1) ? 1 : Integer.parseInt(split[1]);
                    log.info("Candidate mq client for " + queueName + " maxTasks " + maxTask);
                    if (new File(shellScript).exists()) {
                        final Queue queue = new Queue(queueName, shellScript, false);
                        queue.setCorePoolSize(1);
                        queue.setMaxPoolSize(maxTask);
                        queue.setQueueCapacity(1);
                        queues.add(queue);
                        break;
                    } else {
                        log.warn("... skipping, because no startup script found at " + shellScript);
                    }
                }
            }

            if (queues.size() == 0) {
                log.fatal("No queue folders seen in " + messageQueues.getAbsolutePath());
                System.exit(-1);
            }

            // Add the system queue
            queues.add(new Queue("Connection", null, true));

            getInstance(queues, identifier, heartbeatInterval).run();
        }
        System.exit(0);
    }

    public void setContext(GenericXmlApplicationContext context) {
        this.context = context;
    }

    public String getIdentifier() {
        return identifier;
    }

    public void setIdentifier(String identifier) {
        this.identifier = identifier;
    }

    public boolean isPause() {
        return pause;
    }

    public void setPause(boolean pause) {
        this.pause = pause;
    }

    public boolean isStop() {
        return stop;
    }

    public void setStop(boolean stop) {
        this.stop = stop;
    }

    public void setHeartbeatInterval(long heartbeatInterval) {
        this.heartbeatInterval = heartbeatInterval;
    }
}