Java tutorial
/* * 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); } }