org.hyperic.hq.autoinventory.ScanManager.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.autoinventory.ScanManager.java

Source

/*
 * NOTE: This copyright does *not* cover user programs that use HQ
 * program services by normal system calls through the application
 * program interfaces provided as part of the Hyperic Plug-in Development
 * Kit or the Hyperic Client Development Kit - this is merely considered
 * normal use of the program, and does *not* fall under the heading of
 * "derived work".
 * 
 * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
 * This file is part of HQ.
 * 
 * HQ is free software; you can redistribute it and/or modify
 * it under the terms version 2 of the GNU General Public License as
 * published by the Free Software Foundation. This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

package org.hyperic.hq.autoinventory;

import java.util.LinkedList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.common.SystemException;
import org.hyperic.hq.product.AutoinventoryPluginManager;
import org.hyperic.util.AutoApproveConfig;
import org.hyperic.util.timer.StopWatch;

/**
 * The ScanManager controls the Scanner and ensures that only 1 scan is 
 * running at a time.  If someone tries to start a scan while another scan
 * is running, we'll cue up that scan to run immediately after the current
 * scan completes.
 */
public class ScanManager implements ScanListener {

    private final Log log = LogFactory.getLog(ScanManager.class);

    /** Holds the list of queued-up scanners */
    private LinkedList scannerList = new LinkedList();

    /** Which scanner is currently running? */
    private volatile Scanner activeScanner = null;

    /** Who to notify when scans complete */
    private ScanListener listener = null;

    /** Where we get our plugins from */
    private AutoinventoryPluginManager apm = null;

    /** The thread that runs the scan manager */
    private volatile Thread mainThread = null;

    /** Flag that determines whether the manager should exit or keep running */
    private volatile boolean shouldExit = false;

    /** Is there a scan running right now? */
    private volatile boolean scanInProgress = false;

    /** Our runtime autodiscovery scanner, can be null */
    private RuntimeScanner rtScanner = null;

    /** The auto-approval configuration instance*/
    private AutoApproveConfig autoApproveConfig;

    /** When was the last time we ran a runtime scan? */
    private long lastRtScan;

    /** When was the last time we ran a regular defaultscan? */
    private long lastDefaultScan;

    /**
     * Create a scan manager.
     * @param listener The ScanListener to be notified when scans complete.
     * @param log The log to use.
     * @param apm The Autoinventory plugin manager to use for loading
     * platform and server detectors.
     * @param rtScanner The RuntimeScanner to use for runtime scans.
     * This can be null if no runtime scans are to be performed.
     */
    public ScanManager(ScanListener listener, AutoinventoryPluginManager apm, RuntimeScanner rtScanner,
            AutoApproveConfig autoApproveConfig) {
        this.listener = listener;
        this.apm = apm;
        this.rtScanner = rtScanner;
        this.autoApproveConfig = autoApproveConfig;
    }

    /**
     * Startup the ScanManager.  This fires off a Thread that 
     * manages the scan queue.
     */
    public synchronized void startup() {
        shouldExit = false;
        if (rtScanner != null) {
            lastRtScan = System.currentTimeMillis();
        }
        mainThread = new Thread() {
            public void run() {
                try {
                    mainRunLoop();
                } catch (Exception e) {
                    log.error("ERROR in ScanManager thread, exiting: " + e, e);
                }
            }
        };
        mainThread.setPriority(Thread.MIN_PRIORITY);
        mainThread.setDaemon(true);
        mainThread.setName("autoinventory-scanner");
        mainThread.start();
    }

    private void mainRunLoop() {

        while (!shouldExit) {

            synchronized (scannerList) {
                if (scannerList.size() > 0) {
                    activeScanner = (Scanner) scannerList.removeFirst();
                } else {
                    activeScanner = null;
                }
            }

            // Even if no scanner was set, we now run the DefaultScan 
            // periodically.  Find out if we should do that now.
            if (activeScanner == null && isTimeForDefaultScan()) {
                final StopWatch watch = new StopWatch();
                log.info("starting default scan");
                rtScanner.scheduleDefaultScan();
                log.info("default scan complete " + watch);
                lastDefaultScan = System.currentTimeMillis();
                continue;
            }

            if (activeScanner != null) {
                try {
                    scanInProgress = true;
                    activeScanner.start();

                } catch (Exception e) {
                    log.error("Exception starting scanner: " + e, e);

                } catch (NoClassDefFoundError e) {
                    log.error("Error starting scanner: " + e, e);

                } finally {
                    synchronized (scannerList) {
                        activeScanner = null;
                    }
                    scanInProgress = false;
                    // clear the plugin shared data, caches, etc.
                    this.apm.endScan();
                }
            }

            // Check and clear interrupt flag before sleeping
            if (Thread.interrupted())
                continue;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
            }

            if (isTimeForRtScan()) {
                try {
                    final StopWatch watch = new StopWatch();
                    log.info("starting runtime scan");
                    rtScanner.doRuntimeScan();
                    log.info("runtime scan complete " + watch);
                } catch (Exception e) {
                    log.error("Error running runtime autodiscovery scan: " + e, e);
                } finally {
                    lastRtScan = System.currentTimeMillis();
                }
            }
        }
    }

    private boolean isTimeForRtScan() {
        if (rtScanner == null) {
            return false;
        }
        long interval = rtScanner.getScanInterval();
        return (rtScanner != null && System.currentTimeMillis() - lastRtScan > interval);
    }

    private boolean isTimeForDefaultScan() {
        if (rtScanner == null) {
            return false;
        }
        long interval = rtScanner.getDefaultScanInterval();
        return (System.currentTimeMillis() - lastDefaultScan > interval);
    }

    /**
     * Stop the ScanManager.
     * Any currently running scan will be stopped.
     * @param timeout How long to wait for the ScanManager to
     * gracefully exit before Thread.stop-ing it.
     */
    public synchronized void shutdown(long timeout) {
        shouldExit = true;
        if (mainThread != null) {
            mainThread.interrupt();
        } else {
            return;
        }
        long startSleep = System.currentTimeMillis();
        while (mainThread.isAlive()) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
            if (System.currentTimeMillis() - startSleep > timeout) {
                mainThread.stop();
            }
        }
    }

    /**
     * Start a new scan, using the specified scan configuration.
     * @param scanConfig The configuration to use for the scan.
     * @return true if a scan with an identical configuration has
     * already been scheduled, false if this is a new configuration
     * not yet scheduled.
     */
    public boolean queueScan(ScanConfiguration scanConfig) {

        Scanner scanner;

        scanner = new Scanner(scanConfig, this, this.apm, this.autoApproveConfig);

        synchronized (scannerList) {
            if (scannerList.contains(scanner)) {
                return true; //already queued with this config
            }

            scannerList.addLast(scanner);
            return false;
        }
    }

    public void interruptHangingScan() {
        // If the current scan is sleeping in "scanComplete", interrupt the
        // thread.  The server is probably available to receive the report now.
        synchronized (scannerList) {
            if (activeScanner != null) {
                ScanState state = activeScanner.getScanState();
                if (state != null && state.getIsDone()) {
                    mainThread.interrupt();
                }
            }
        }
    }

    /**
     * Stops the currently running scan.
     * @return true if a scan was actually running and was interrupted, 
     * false otherwise.
     */
    public boolean stopScan() throws AutoinventoryException {
        boolean wasScanRunning = false;
        synchronized (scannerList) {
            if (activeScanner != null) {
                activeScanner.stop();
                if (mainThread != null) {
                    mainThread.interrupt();
                }
                wasScanRunning = true;
            }
        }

        long startWait = System.currentTimeMillis();
        while (scanInProgress) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
            if (System.currentTimeMillis() - startWait > 60000) {
                throw new AutoinventoryException("Scan did not stop " + "within 1 minute: " + activeScanner);
            }
        }

        return wasScanRunning;
    }

    /**
     * Get the status of the currently running scan.
     * @return A ScanState object representing the current status
     * of the running scan.
     */
    public ScanState getStatus() {
        synchronized (scannerList) {
            if (activeScanner != null) {
                return activeScanner.getScanState();
            }
        }
        return null;
    }

    /**
     * @return true if there is a scan currently running, false otherwise.
     */
    public boolean isScanRunning() {
        return (activeScanner != null);
    }

    public boolean isScanQueued() {
        return this.scannerList.size() != 0;
    }

    public void scanComplete(ScanState state) throws AutoinventoryException, SystemException {
        this.listener.scanComplete(state);
    }
}