/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.notifd; import java.util.List; import java.util.SortedMap; import org.opennms.core.utils.LogUtils; import org.opennms.core.utils.TimeConverter; /** * This class is used as a thread for executing notices for events that are * discovered by the notice daemon. The notices are read from an scheduler queue * and the processes are created by the fiber. Each created process is added to * garbage collection list that is periodically polled and culled based upon the * status of the process or how long the process is run. If the process has run * long than allocated it is terminated during collection. * * @author <a href="mailto:jason@opennms.org">Jason Johns</a> * @author <a href="http://www.opennms.org/>OpenNMS</a> */ public class DefaultQueueHandler implements NotifdQueueHandler { /** * The input queue of runnable commands. */ private NoticeQueue m_noticeQueue; /** * The name of this Fiber */ private String m_queueID; /** * How long to sleep between processing more notices */ private long m_interval; /** * The status of this fiber. */ private int m_status; /** * <p>Constructor for DefaultQueueHandler.</p> */ public DefaultQueueHandler() { m_status = START_PENDING; } /** {@inheritDoc} */ public void setQueueID(final String queueID) { m_queueID = queueID; } /** {@inheritDoc} */ public synchronized void setNoticeQueue(final NoticeQueue noticeQueue) { m_noticeQueue = noticeQueue; } /** {@inheritDoc} */ public void setInterval(final String interval) { m_interval = TimeConverter.convertToMillis(interval); } /** * The main worker of the fiber. This method is executed by the encapsulated * thread to read commands from the execution queue and to execute those * commands. If the thread is interrupted or the status changes to * <code>STOP_PENDING</code> then the method will return as quickly as * possible. */ public void run() { synchronized (this) { m_status = RUNNING; } for (;;) { synchronized (this) { // if stopped or stop pending then break out if (m_status == STOP_PENDING || m_status == STOPPED) { break; } // if paused or pause pending then block while (m_status == PAUSE_PENDING || m_status == PAUSED) { m_status = PAUSED; try { wait(); } catch (final InterruptedException ex) { // exit break; } } // if resume pending then change to running if (m_status == RESUME_PENDING) { m_status = RUNNING; } } processQueue(); synchronized (this) { // wait for the next iteration try { wait(m_interval); } catch (final InterruptedException ex) { // exit break; } } } // end infinite loop synchronized (this) { m_status = STOPPED; } } // end run /** * <p>processQueue</p> */ public void processQueue() { if (m_noticeQueue != null) { synchronized(m_noticeQueue) { try { final Long now = System.currentTimeMillis(); final SortedMap<Long, List<NotificationTask>> readyNotices = m_noticeQueue.headMap(now); for (final List<NotificationTask> list : readyNotices.values()) { for (final NotificationTask task : list) { startTask(task); } } readyNotices.clear(); if (LogUtils.isDebugEnabled(this) && m_noticeQueue != null && m_noticeQueue.size() > 0) { LogUtils.debugf(this, "current state of tree: %s", m_noticeQueue); } } catch (final Throwable e) { LogUtils.errorf(this, e, "failed to start notification task"); } } } } private void startTask(final NotificationTask task) { if (!task.isStarted()) task.start(); } /** * Starts the fiber. If the fiber has already been run or is currently * running then an exception is generated. The status of the fiber is * updated to <code>STARTING</code> and will transition to <code> * RUNNING</code> * when the fiber finishes initializing and begins processing the * encapsulated queue. * * @throws java.lang.IllegalStateException * Thrown if the fiber is stopped or has never run. */ public synchronized void start() { m_status = STARTING; final Thread thread = new Thread(this, this.getClass().getSimpleName() + "-" + m_queueID); thread.start(); } /** * Stops a currently running fiber. If the fiber has already been stopped * then the command is silently ignored. If the fiber was never started then * an exception is generated. * * @throws java.lang.IllegalStateException * Thrown if the fiber was never started. */ public synchronized void stop() { if (m_status != STOPPED) m_status = STOP_PENDING; notifyAll(); } /** * Pauses a currently running fiber. If the fiber was not in a running or * resuming state then the command is silently discarded. If the fiber is * not running or has terminated then an exception is generated. * * @throws java.lang.IllegalStateException * Thrown if the fiber is stopped or has never run. */ public synchronized void pause() { if (m_status == RUNNING || m_status == RESUME_PENDING) { m_status = PAUSE_PENDING; notifyAll(); } } /** * Resumes the fiber if it is paused. If the fiber was not in a paused or * pause pending state then the request is discarded. If the fiber has not * been started or has already stopped then an exception is generated. * * @throws java.lang.IllegalStateException * Thrown if the fiber is stopped or has never run. */ public synchronized void resume() { if (m_status == PAUSED || m_status == PAUSE_PENDING) { m_status = RESUME_PENDING; notifyAll(); } } /** * Returns the name of this fiber. * * @return The name of the fiber. */ public String getName() { return m_queueID; } /** * Returns the current status of the pausable fiber. * * @return The current status of the fiber. * @see org.opennms.core.fiber.PausableFiber * @see org.opennms.core.fiber.Fiber */ public synchronized int getStatus() { return m_status; } }