org.hyperic.util.file.match.Matcher.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.util.file.match.Matcher.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.util.file.match;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;

import org.apache.tools.ant.types.selectors.FileSelector;

import org.hyperic.sigar.FileSystem;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;

/**
 * Implements a powerful file/directory matcher on top of Ant's fileset
 * classes.
 */
public class Matcher {

    /** 
     * Construct an Matcher.
     */
    public Matcher() {
    }

    /**
     * Sets up the appropriate MatcherScanners to use for the search.
     * @param config The config to use to initialize
     * @return A List of MatcherScanners to use for the search.
     */
    private List initScanners(MatcherConfig config, FileSystem[] filesystems, MatchResults results) {

        List dirs = config.getSearchDirs();
        String dir;
        int i, j;
        MatcherScanner scanner;
        List scanners = new ArrayList();

        List selectorList = config.getMatchSelectors();
        MatchSelector[] selectors;
        MasterMatchSelector masterSelector;
        FileSelector[] masterSelectorArray;

        List excludes = config.getExcludePatterns();
        Log log = config.getLog();
        String[] excludesArray;
        selectors = new MatchSelector[selectorList.size()];
        for (i = 0; i < selectors.length; i++) {
            selectors[i] = (MatchSelector) selectorList.get(i);
        }
        masterSelectorArray = new FileSelector[1];
        masterSelectorArray[0] = new MasterMatchSelector(selectors, config.getAllowMultipleMatches());

        excludesArray = new String[excludes.size()];
        for (i = 0; i < excludesArray.length; i++) {
            excludesArray[i] = excludes.get(i).toString();
        }

        for (i = 0; i < dirs.size(); i++) {
            dir = (String) dirs.get(i);
            if (shouldSkip(dir, log, results))
                continue;
            if (config.getFSTypes() != MatcherConfig.FS_ALL) {
                if (!isFSTypeMatch(dir, config.getFSTypes(), filesystems, log))
                    continue;
            }

            scanner = new MatcherScanner();
            scanner.setLog(log);
            scanner.setBasedir(new File(dir));
            scanner.setSelectors(masterSelectorArray);
            scanner.setExcludes(excludesArray);
            scanner.setFollowSymlinks(config.getFollowSymlinks());
            scanner.setMatcherInterruptCB(config.getMatcherInterruptCB());
            scanner.setMatcherProgressCB(config.getMatcherProgressCB());
            scanner.setMaxDepth(config.getMaxDepth());
            scanners.add(scanner);
        }

        return scanners;
    }

    /**
     * Determine if the dir is on a filesystem that we should
     * be searching.
     * @param dir The name of the directory.
     * @param fstypes The filesystem types we're supposed to search.
     * @param filesystems The filesystems that sigar detected.
     * @param log The log to use for errors and warnings.
     * @return true if the directory should be included in the search, 
     * false otherwise.
     */
    private boolean isFSTypeMatch(String dir, int fstypes, FileSystem[] filesystems, Log log) {
        String longestMatch = "";
        int longestMatchIndex = -1;
        String absPath = (new File(dir)).getAbsolutePath();
        String fsMountPoint;

        if (filesystems == null) {
            if (log != null) {
                log.error("matcher: filesystems array was never initialized.");
            }
            throw new IllegalArgumentException("filesystems array was never " + "initialized.");
        }

        for (int i = 0; i < filesystems.length; i++) {
            fsMountPoint = filesystems[i].getDirName();
            if (absPath.startsWith(fsMountPoint) && fsMountPoint.length() > longestMatch.length()) {
                longestMatch = fsMountPoint;
                longestMatchIndex = i;
            }
        }
        if (longestMatchIndex == -1) {
            if (log != null) {
                log.warn("Directory " + dir + " did not match " + "any filesystems, it will not be searched.");
            }
            return false;
        }

        return isCandidateFS(fstypes, filesystems[longestMatchIndex], log);
    }

    /**
     * Determine if the given filesystem is OK to search, based on
     * the value of fstype which tells us what filesystem types we
     * are supposed to search.
     */
    public boolean isCandidateFS(int fstype, FileSystem fs, Log log) {

        switch (fs.getType()) {
        case FileSystem.TYPE_UNKNOWN:
            if (log != null) {
                log.warn("Encountered UNKNOWN filesystem (device=" + fs.getDevName() + "): " + fs.getDirName());
            }
            return false;

        case FileSystem.TYPE_NONE:
            if (log != null) {
                log.warn("Encountered NONE filesystem (device=" + fs.getDevName() + "): " + fs.getDirName());
            }
            return false;

        case FileSystem.TYPE_LOCAL_DISK:
            return (fstype == MatcherConfig.FS_ALL || fstype == MatcherConfig.FS_LOCAL);

        case FileSystem.TYPE_NETWORK:
            return (fstype == MatcherConfig.FS_ALL || fstype == MatcherConfig.FS_NETWORK);

        case FileSystem.TYPE_RAM_DISK:
        case FileSystem.TYPE_CDROM:
        case FileSystem.TYPE_SWAP:
            return false;

        default:
            if (log != null) {
                log.warn("Encountered filesystem with invalid type (" + fs.getType() + ") (device="
                        + fs.getDevName() + "): " + fs.getDirName());
            }
            return false;
        }
    }

    private FileSystem[] loadFilesystems(MatcherConfig config) throws SigarException {

        Log log = config.getLog();
        FileSystem[] filesystems;

        if (config.getFSTypes() != MatcherConfig.FS_ALL) {
            Sigar sigar = new Sigar();
            try {
                filesystems = sigar.getFileSystemList();
                return filesystems;

            } catch (SigarException se) {
                if (log != null) {
                    log.error("matcher: error getting " + "available filesystems:" + se, se);
                }
                throw se;

            } finally {
                sigar.close();
            }
        }
        return null;
    }

    /**
     * Get the matches for this search.
     * @return A Map representing the matches.  The keys in the Map are
     * the keys that each MatchSelector in the MatcherConfig was
     * initialized with in its constructor.  The values are Lists, where
     * each element in the List is a String representing the full path
     * of the matched path.
     * @exception MatcherInterruptedException If the search was interrupted
     * before it could be completed.  In this case, you can get the matches
     * so far by calling getMatchesSoFar on the MatcherInterruptedException
     * object.
     * @exception SigarException If an error occurs reading the available
     * filesystems - this can only happen if the config's getFSTypes returns
     * a value other than MatcherConfig.FS_ALL.
     */
    public synchronized MatchResults getMatches(MatcherConfig config)
            throws MatcherInterruptedException, SigarException {

        int i, j;
        List scanners;
        MatcherScanner scanner;
        MatchResults results = new MatchResults();
        File f;
        Log log = config.getLog();
        FileSystem[] filesystems = null;

        filesystems = loadFilesystems(config);
        scanners = initScanners(config, filesystems, results);

        for (i = 0; i < scanners.size(); i++) {

            scanner = (MatcherScanner) scanners.get(i);
            scanner.initMatches(results.matches);

            try {
                scanner.doScan();

            } catch (MatcherInterruptedException mie) {
                mie.setMatchesSoFar(scanner.getMatches());
                if (log != null) {
                    log.warn("matcher: search interrupted.");
                }
                throw mie;

            } catch (Exception e) {
                // huh?
                scanner.addError(new MatcherException("matcher: search error", e));
                if (log != null) {
                    log.error("matcher: search error: " + e, e);
                }
            }

            results.matches = scanner.getMatches();
            if (log != null) {
                log.debug("results.matches=" + results.matches);
            }
            results.errors.addAll(scanner.getErrors());
        }

        return results;
    }

    /**
     * Should we skip a directory completely?
     * @return true if dir is null, if dir is not a directory,
     * if we can't read dir, or if dir does not exist.
     */
    private boolean shouldSkip(String dir, Log log, MatchResults results) {
        File dirFile;
        String msg;

        // Should never happen
        if (dir == null) {
            msg = "matcher: ignoring null dir.";
            if (log != null) {
                log.info(msg);
            }
            results.errors.add(new MatcherException(msg));
            return true;
        }

        dirFile = new File(dir);
        if (!dirFile.exists()) {
            msg = "matcher: ignoring non-existent dir: " + dirFile.getAbsolutePath();
            if (log != null) {
                log.info(msg);
            }
            results.errors.add(new MatcherException(msg));
            return true;
        }
        if (!dirFile.canRead()) {
            msg = "matcher: ignoring unreadable dir: " + dirFile.getAbsolutePath();
            if (log != null) {
                log.info(msg);
            }
            results.errors.add(new MatcherException(msg));
            return true;
        }
        if (!dirFile.isDirectory()) {
            msg = "matcher: ignoring non-dir: " + dirFile.getAbsolutePath();
            if (log != null) {
                log.info(msg);
            }
            results.errors.add(new MatcherException(msg));
            return true;
        }
        return false;
    }
}