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

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.autoinventory.ScanState.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.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.appdef.shared.AIPlatformValue;
import org.hyperic.hq.appdef.shared.AIServerExtValue;
import org.hyperic.hq.appdef.shared.AIServerValue;
import org.hyperic.hq.product.ServerResource;
import org.hyperic.util.StringUtil;
import org.hyperic.util.StringifiedException;

public class ScanState {

    private static HashMap installdirExcludes = new HashMap();
    private static List installdirExcludesPrefixes = new ArrayList();
    private static final Log _log = LogFactory.getLog(ScanState.class);

    static {
        loadInstalldirExcludes();
    }

    private DateFormat dateFmt = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);

    private ScanStateCore _core;

    /** ScanMethodClassName->ScanMethod */
    private Map _scanMethods = null;

    private boolean _isDefaultScan = false;

    public ScanState() {
        _core = new ScanStateCore();
    }

    public ScanState(ScanStateCore core) {
        _core = core;
    }

    public ScanStateCore getCore() {
        return _core;
    }

    public void setCore(ScanStateCore core) {
        _core = core;
    }

    public boolean getIsDefaultScan() {
        return _isDefaultScan;
    }

    public void setIsDefaultScan(boolean b) {
        _isDefaultScan = b;
    }

    public boolean getAreServersIncluded() {
        return _core.getAreServersIncluded();
    }

    public void setAreServersIncluded(boolean b) {
        _core.setAreServersIncluded(b);
    }

    public long getStartTime() {
        return _core.getStartTime();
    }

    /**
     * @return the formatted start time 
     */
    public String getStartTimeStr() {
        if (getStartTime() == 0)
            return "00/00/00 00:00:00";

        return dateFmt.format(new Long(getStartTime()));
    }

    public void setStartTime(long startTime) {
        _core.setStartTime(startTime);
    }

    public long getEndTime() {
        return _core.getEndTime();
    }

    public String getEndTimeStr() {
        if (getEndTime() == 0)
            return "00/00/00 00:00:00";

        return dateFmt.format(new Long(getEndTime()));
    }

    public void setEndTime(long endTime) {
        _core.setEndTime(endTime);
    }

    /**
     * @return the formatted relapsed time 
     */
    public String getElapsedTimeStr() {
        long end = 0;

        // if the start time is zero, return no elapsed time
        if (getStartTime() == 0)
            return StringUtil.formatDuration(0);

        if (getEndTime() == 0)
            end = (new Date()).getTime();
        else
            end = getEndTime();

        return StringUtil.formatDuration(end - getStartTime());
    }

    public boolean getIsDone() {
        return _core.getIsDone();
    }

    public void setIsDone() {
        _core.setIsDone(true);
    }

    public boolean getIsInterrupted() {
        return _core.getIsInterrupted();
    }

    public void setIsInterrupted() {
        _core.setIsInterrupted(true);
    }

    public StringifiedException getGlobalException() {
        return _core.getGlobalException();
    }

    public void setGlobalException(Throwable _globalException) {
        _core.setGlobalException(new StringifiedException(_globalException));
    }

    /**
     * Tell the scan state what scan methods will be run.
     * @param scanMethods An array of ScanMethod class names that
     * represent the ScanMethods that will be run in this scan.
     */
    public void setScanMethods(String[] scanMethods) throws AutoinventoryException {

        // Walk thru the list and construct the ScanMethodState[] array
        ScanMethodState[] smStates = new ScanMethodState[scanMethods.length];
        for (int i = 0; i < scanMethods.length; i++) {
            smStates[i] = new ScanMethodState();
            smStates[i].setMethodClass(scanMethods[i]);
        }
        _core.setScanMethodStates(smStates);

        setupMethodHash();
    }

    /**
     * Setup our internal hash of ScanMethodClassName->ScanMethod
     */
    protected void setupMethodHash() throws AutoinventoryException {

        _scanMethods = new HashMap();

        ScanMethodState[] smStates = _core.getScanMethodStates();
        if (smStates == null)
            return;

        ScanMethod method;
        String methodClass;
        for (int i = 0; i < smStates.length; i++) {
            methodClass = smStates[i].getMethodClass();
            try {
                method = (ScanMethod) Class.forName(methodClass).newInstance();
            } catch (Exception e) {
                throw new AutoinventoryException(methodClass + ": error instantiating: " + e, e);
            }
            _scanMethods.put(methodClass, method);
        }
    }

    public boolean completedOK() {
        return _core.getIsDone() && (!hasExceptions()) && (!_core.getIsInterrupted());
    }

    public boolean hasExceptions() {
        ScanMethodState[] smStates = _core.getScanMethodStates();
        StringifiedException[] exceptions;
        for (int i = 0; i < smStates.length; i++) {
            exceptions = smStates[i].getExceptions();
            if (exceptions != null && exceptions.length > 0) {
                return true;
            }
        }
        return false;
    }

    public void initStartTime() {
        _core.setStartTime(System.currentTimeMillis());
    }

    public void initEndTime() {
        _core.setEndTime(System.currentTimeMillis());
    }

    public long getScanDuration() {
        long startTime = _core.getStartTime();
        long endTime = _core.getEndTime();
        if (endTime == 0) {
            if (startTime == 0) {
                return 0;
            }
            return System.currentTimeMillis() - startTime;
        }
        return endTime - startTime;
    }

    public AIPlatformValue getPlatform() {
        return _core.getPlatform();
    }

    public void setPlatform(AIPlatformValue platform) {
        _core.setPlatform(platform);
    }

    public String getCertDN() {
        return _core.getPlatform().getCertdn();
    }

    public void setCertDN(String certDN) {
        _core.setCertDN(certDN);
    }

    public void addScanException(ScanMethod scanMethod, Throwable t) {

        ScanMethodState smState = findSMState("addScanException", scanMethod);
        smState.addException(new StringifiedException(t));
    }

    public void addScanExceptions(ScanMethod scanMethod, Throwable[] t) {

        ScanMethodState smState = findSMState("addScanException", scanMethod);
        smState.addExceptions(t);
    }

    public void setScanStatus(ScanMethod scanMethod, String status) {
        ScanMethodState smState = findSMState("addScanException", scanMethod);
        smState.setStatus(status);
    }

    public ScanMethodState[] getScanMethodStates() {
        ScanMethodState[] smStates = _core.getScanMethodStates();
        return smStates;
    }

    //XXX temporary during refactoring
    private AIServerValue getServerValue(Object o) {
        AIServerValue server;
        if (o instanceof AIServerValue) {
            server = (AIServerValue) o;
        } else {
            server = (AIServerValue) ((ServerResource) o).getResource();
        }

        if (!server.cTimeHasBeenSet()) {
            server.setCTime(new Long(System.currentTimeMillis()));
        }

        return server;
    }

    private List excludeServers(List servers) {
        if (installdirExcludes.size() == 0) {
            return servers;
        }

        ArrayList includes = new ArrayList();

        for (int i = 0; i < servers.size(); i++) {
            Object server = servers.get(i);
            String installpath = getServerValue(server).getInstallPath();
            boolean exclude = false;
            if (installdirExcludes.get(installpath) != null) {
                continue;
            }
            for (int j = 0; j < installdirExcludesPrefixes.size(); j++) {
                String prefix = (String) installdirExcludesPrefixes.get(j);
                if (installpath.startsWith(prefix)) {
                    exclude = true;
                    break;
                }
            }
            if (!exclude) {
                includes.add(server);
            }
        }

        return includes;
    }

    /**
     * Add servers to the list of servers detected for a particular 
     * scan method.
     * @param scanMethod The scan method to add servers to.
     * @param servers A List of AIServer objects representing
     * the servers (and their services) that were detected and should be
     * added and associated with the given scan method.
     */
    public void addServers(ScanMethod scanMethod, List servers) {
        servers = excludeServers(servers);
        if (servers.isEmpty()) {
            return;
        }
        ScanMethodState smState = findSMState("addServers", scanMethod);
        AIServerValue[] newServers;
        AIServerValue[] existingServers = smState.getServers();
        if (existingServers == null) {
            newServers = new AIServerValue[servers.size()];
            for (int i = 0; i < newServers.length; i++) {
                newServers[i] = getServerValue(servers.get(i));
            }

        } else {
            List<AIServerValue> allServers = new ArrayList<AIServerValue>(Arrays.asList(existingServers));
            //Get rid of any servers we have already discovered (by autoinventoryidentifier). 
            //ServerDetectors are ordered, so first one should always win
            for (Iterator iterator = servers.iterator(); iterator.hasNext();) {
                AIServerValue server = getServerValue(iterator.next());
                String identifier = server.getAutoinventoryIdentifier();
                boolean newIdentifier = true;
                for (AIServerValue existingServer : existingServers) {
                    if (existingServer.getAutoinventoryIdentifier().equals(identifier)) {
                        newIdentifier = false;
                        break;
                    }
                }
                if (newIdentifier) {
                    allServers.add(server);
                }
            }
            newServers = allServers.toArray(new AIServerValue[allServers.size()]);
        }
        smState.setServers(newServers);
    }

    /**
     * For debugging purposes, print out the servers that were
     * detected.
     */
    public void printServers() {

        ScanMethodState[] smStates = _core.getScanMethodStates();
        AIServerValue[] servers;
        for (int i = 0; i < smStates.length; i++) {
            System.err.println("Detected by: " + smStates[i].getMethodClass());
            servers = smStates[i].getServers();
            for (i = 0; i < servers.length; i++) {
                System.err.println("\t" + servers[i]);
            }
        }
    }

    /**
     * For debugging purposes, print stack traces for all exceptions
     */
    public void printStackTraces() {
        ScanMethodState[] smStates = _core.getScanMethodStates();
        StringifiedException[] exc;
        for (int i = 0; i < smStates.length; i++) {
            exc = smStates[i].getExceptions();
            if (exc != null && exc.length > 0) {
                System.err.println("Exceptions for method " + smStates[i].getMethodClass() + ":");
                for (int j = 0; j < exc.length; j++) {
                    System.err.println("\n" + exc[j].getStackTrace());
                }
            }
        }
    }

    /**
     * For debugging and command-line use, pretty-print full status info.
     * @param out The stream to write to.
     */
    public void printFullStatus(PrintStream out) throws AutoinventoryException {

        StringifiedException globalEx = _core.getGlobalException();
        ScanMethodState[] smStates = _core.getScanMethodStates();

        if (globalEx != null) {
            out.println("Severe failure: " + globalEx);
            out.println(globalEx.getStackTrace());
        }

        if (smStates == null) {
            out.println("scan not yet started.");
            return;
        }
        printMainStatus(out);

        for (int i = 0; i < smStates.length; i++) {
            printMethodStatus(smStates[i], out);
        }
    }

    public void printMainStatus(PrintStream out) {

        out.print("\nOVERALL STATUS: ");

        String status = null;
        if (_core.getIsInterrupted()) {
            status = "interrupted before normal completion";

        } else if (_core.getIsDone()) {
            status = "completed";

        } else {
            status = "scan in progress";
        }

        if (_core.getGlobalException() != null) {
            status += ", however a general scanning error occurred";
        } else if (hasExceptions()) {
            status += " successfully, however one or more scan methods had errors";
        } else if (_core.getIsDone()) {
            status += " successfully with no errors";
        }

        out.println(status);

        String duration = StringUtil.formatDuration(getScanDuration());
        out.println("Run time: " + duration);

        AIPlatformValue platform = _core.getPlatform();
        if (platform != null) {
            out.println("\nPlatform Detected:");
            out.println("\t" + platform);
            out.println("\tIP addresses: " + StringUtil.arrayToString(platform.getAIIpValues()));
        } else {
            out.println("\nNo Platform Detected!");
        }
    }

    public void printMethodStatus(ScanMethodState smState, PrintStream out) throws AutoinventoryException {

        ScanMethod method = findScanMethod(smState.getMethodClass());
        out.println("\n" + method.getName() + ":");

        // Print exception (if any)
        StringifiedException[] t = smState.getExceptions();
        String status = smState.getStatus();
        if (t != null && t.length > 0) {
            out.println("\t* SCAN FAILED: ");
            if (status != null) {
                out.println("\t* Last status before failure: " + status);
            } else {
                out.println("\t* No status message available.");
            }
            for (int i = 0; i < t.length; i++) {
                out.println("\t* " + t[i].toString());
                out.println("\t* Stack Trace:");
                out.println(t[i].getStackTrace());
            }

        } else {
            if (status == null) {
                out.println("\t* Status: unknown");
            } else {
                out.println("\t* Status: " + status);
            }
        }

        // PRINT SERVERS DETECTED
        AIServerValue[] servers = smState.getServers();
        if (servers == null || servers.length == 0) {
            out.println("\t* No Servers Detected");

        } else {
            out.println("\t* Detected Servers:");
            for (int i = 0; i < servers.length; i++) {
                out.println("\t" + servers[i]);
            }
        }
        out.println("\n");
    }

    public String toString() {
        if (_core == null)
            return "[ScanState]";
        return _core.toString();
    }

    /**
     * Get the set of all servers detected in this autoinventory scan.
     * This is the method that reconciles the fact that multiple scan methods
     * may have discovered the same server.  We assemble the list of all
     * servers by iterating over each scan method in order of authority level.
     * The scan methods with the highest authority level have their servers
     * added first.  Scan methods with lower authority levels will have their
     * servers added as long as they have a different autoinventory ID from
     * ones discovered by methods with higher authority levels.
     * @return A Set of AIServerValue objects.  The Set uniqueness
     * is based on the server autoinventory identifier, which is
     * usually the same as the install path.
     */
    public Set getAllServers() throws AutoinventoryException {

        // allServers will guarantee uniqueness on the AIID.
        Set allServers = new TreeSet(COMPARE_AIID);

        // Put all the scan methods in a list
        Map scanMethods = getScanMethodMap();
        Iterator iter = scanMethods.keySet().iterator();
        List smList = new ArrayList();
        while (iter.hasNext()) {
            smList.add(scanMethods.get(iter.next()));
        }

        // Sort the scan methods by authority level.
        Collections.sort(smList, COMPARE_AUTH);

        // Iterate over the scan methods
        AIServerValue[] servers;
        String methodClass;
        ScanMethod method;
        ScanMethodState smState;
        for (int i = 0; i < smList.size(); i++) {

            method = (ScanMethod) smList.get(i);
            smState = findSMState("getAllServers", method);
            methodClass = smState.getMethodClass();

            servers = smState.getServers();
            if (servers != null) {
                for (int j = 0; j < servers.length; j++) {
                    if (!allServers.add(servers[j])) {
                        if (_log != null) {
                            _log.info("Server not added because another scan " + "method already detected it:"
                                    + servers[j]);
                        }
                    }
                }
            }
        }

        Map mServers = new HashMap();
        //look for servers with the same Metric Connect HashCode
        //for example, two JBoss servers with different installpath
        //but the same config: jnp://localhost:1099
        for (Iterator allIter = allServers.iterator(); allIter.hasNext();) {
            Object o = allIter.next();

            if (!(o instanceof AIServerExtValue)) {
                continue;
            }

            AIServerExtValue server = (AIServerExtValue) o;

            if (!server.getAutoEnable()) {
                continue;
            }

            int hashCode = server.getMetricConnectHashCode();
            if (hashCode == 0) {
                continue;
            }

            Integer key = new Integer(hashCode);
            AIServerExtValue cServer = (AIServerExtValue) mServers.get(key);

            if (cServer == null) {
                //based on ScanImpl authority, the first server
                //found is the most likely to be running.
                mServers.put(key, server);
            } else {
                //found a server with the same connect config
                //turn off AutoEnable
                server.setAutoEnable(false);
                //disable metric collection
                server.unsetMeasurementConfig();

                if (_log != null) {
                    _log.info("Turning off AutoEnable for server " + server.getName() + " ["
                            + server.getInstallPath() + "]" + ", has the same metric connect config as "
                            + cServer.getName() + " [" + cServer.getInstallPath() + "]");
                }
            }
        }

        return allServers;
    }

    protected ScanMethodState findSMState(String caller, ScanMethod scanMethod) {

        ScanMethodState[] smStates = _core.getScanMethodStates();
        String smClassName = scanMethod.getClass().getName();
        for (int i = 0; i < smStates.length; i++) {
            if (smStates[i].getMethodClass().equals(smClassName)) {
                return smStates[i];
            }
        }

        throw new IllegalArgumentException("Error finding smState: " + smClassName + ", caller=" + caller);
    }

    protected ScanMethod findScanMethod(String methodClass) throws AutoinventoryException {

        Map scanMethods = getScanMethodMap();

        ScanMethod m = (ScanMethod) scanMethods.get(methodClass);
        if (m != null)
            return m;

        throw new IllegalArgumentException("ScanMethod not found: " + methodClass);
    }

    private Map getScanMethodMap() throws AutoinventoryException {
        if (_scanMethods == null)
            setupMethodHash();
        return _scanMethods;
    }

    public boolean isSameState(ScanState other) throws AutoinventoryException {

        // Compare platform attributes
        AIPlatformValue p1, p2;
        p1 = getPlatform();
        p2 = other.getPlatform();

        if (!AICompare.compareAIPlatforms(p1, p2))
            return false;

        Set servers1, servers2;
        servers1 = getAllServers();
        servers2 = other.getAllServers();
        if (!AICompare.compareAIServers(servers1, servers2))
            return false;

        return true;
    }

    private static Comparator COMPARE_AIID = new ServerComparator_AIID();

    static class ServerComparator_AIID implements Comparator {
        public ServerComparator_AIID() {
        }

        public int compare(Object o1, Object o2) {
            if (o1 instanceof AIServerValue && o2 instanceof AIServerValue) {
                return ((AIServerValue) o2).getAutoinventoryIdentifier()
                        .compareTo(((AIServerValue) o1).getAutoinventoryIdentifier());
            }
            return 0; // all other object are "equal"
        }

        public boolean equals(Object o) {
            return false;
        }
    }

    private static Comparator COMPARE_AUTH = new ServerComparator_AuthLevel();

    static class ServerComparator_AuthLevel implements Comparator {
        public ServerComparator_AuthLevel() {
        }

        public int compare(Object o1, Object o2) {
            if (o1 instanceof ScanMethod && o2 instanceof ScanMethod) {
                return ((ScanMethod) o2).getAuthorityLevel() - ((ScanMethod) o1).getAuthorityLevel();
            }
            return 0; // all other object are "equal"
        }

        public boolean equals(Object o) {
            return false;
        }
    }

    //any installpath found in ~/.hq/installdir.excludes
    //will not be reported by AI
    private static void loadInstalldirExcludes() {
        String path = System.getProperty("user.home") + File.separator + ".hq" + File.separator
                + "installdir.excludes";
        File excludes = new File(path);
        if (!excludes.exists()) {
            return;
        }

        FileReader is = null;
        try {
            is = new FileReader(excludes);
            BufferedReader in = new BufferedReader(is);
            String line;
            while ((line = in.readLine()) != null) {
                line = line.trim();
                if (line.length() == 0) {
                    continue;
                }
                if (line.charAt(0) == '#') {
                    continue;
                }
                if (line.endsWith("*")) {
                    line = line.substring(0, line.length() - 1);
                    installdirExcludesPrefixes.add(line);
                }
                installdirExcludes.put(line, Boolean.TRUE);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
    }
}