spade.utility.CommonFunctions.java Source code

Java tutorial

Introduction

Here is the source code for spade.utility.CommonFunctions.java

Source

/*
 --------------------------------------------------------------------------------
 SPADE - Support for Provenance Auditing in Distributed Environments.
 Copyright (C) 2015 SRI International
    
 This program 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.
    
 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, see <http://www.gnu.org/licenses/>.
 --------------------------------------------------------------------------------
 */
package spade.utility;

import java.io.File;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;

import spade.core.Settings;

public class CommonFunctions {

    private static final Logger logger = Logger.getLogger(CommonFunctions.class.getName());
    // Group 1: key
    // Group 2: value
    private static final Pattern pattern_key_value = Pattern
            .compile("(\\w+)=\"*((?<=\")[^\"]+(?=\")|([^\\s]+))\"*");

    /**
     * Converts a string of the format [a="b" c=d e=f] into a map of key values
     * Any portions of the string not matching the pattern [a="b"] or [c=d] are ignored
     * 
     * Uses the pattern {@link #pattern_key_value pattern_key_value}
     * 
     * @param messageData string to parse
     * @return a hashmap
     */
    public static Map<String, String> parseKeyValPairs(String messageData) {
        /*
          * Takes a string with keyvalue pairs and returns a Map Input e.g.
          * "key1=val1 key2=val2" etc. Input string validation is callee's
          * responsibility
          */
        Map<String, String> keyValPairs = new HashMap<String, String>();
        if (messageData == null || messageData.trim().isEmpty()) {
            return keyValPairs;
        }
        Matcher key_value_matcher = pattern_key_value.matcher(messageData);
        while (key_value_matcher.find()) {
            keyValPairs.put(key_value_matcher.group(1).trim(), key_value_matcher.group(2).trim());
        }
        return keyValPairs;
    }

    /**
     * Gets the default config file path by class.
     * Reads the config file as key value map (if the file exists)
     * Overwrites the config key values by key value specified in arguments
     * Returns the final map if success
     * 
     * @param clazz the class to get the default config file for
     * @param arguments arguments as key value (can be null or empty)
     * @return map
     * @throws Exception 1) Failed to read config file, 2) Failed to check if file exists, 3) Failed to check if file is regular, 4) Failed to create file object
     */
    public static Map<String, String> getGlobalsMapFromConfigAndArguments(Class<?> clazz, String arguments)
            throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        String configFilePath = Settings.getDefaultConfigFilePath(clazz);
        try {
            File configFile = new File(configFilePath);
            try {
                if (configFile.exists() && configFile.isFile()) {
                    try {
                        map.putAll(FileUtility.readConfigFileAsKeyValueMap(configFilePath, "="));
                    } catch (Exception e) {
                        throw new Exception("Failed to read config file: " + configFilePath, e);
                    }
                }
            } catch (Exception e) {
                throw new Exception("Failed to check if file exists, and is regular file: " + configFilePath, e);
            }
        } catch (Exception e) {
            throw new Exception("Failed to create file object: " + configFilePath, e);
        }

        if (arguments != null) {
            map.putAll(parseKeyValPairs(arguments));
        }

        return map;
    }

    /**
     * Convenience wrapper function for Integer.parseInt. Suppresses the exception and returns
     * the given default value in that case
     * 
     * @param string string to parse
     * @param defaultValue value to return in case of exception
     * @return integer representation of the string
     */
    public static Integer parseInt(String string, Integer defaultValue) {
        try {
            return Integer.parseInt(string);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Convenience wrapper function for Long.parseLong. Suppresses the exception and returns
     * the given default value in that case
     * 
     * @param str string to parse
     * @param defaultValue value to return in case of exception
     * @return long representation of the string
     */
    public static Long parseLong(String str, Long defaultValue) {
        try {
            return Long.parseLong(str);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Convenience wrapper function for Double.parseDouble. Suppresses the exception and returns
     * the given default value in that case
     * 
     * @param str string to parse
     * @param defaultValue value to return in case of exception
     * @return double representation of the string
     */
    public static Double parseDouble(String str, Double defaultValue) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Convenience function to get a map with keys converted to lowercase.
     * 
     * Responsibility of the caller to make sure that different keys don't 
     * become the same after converted to lowercase.
     * 
     * Throws NPE if the map is the null
     * 
     * @param map map to convert
     * @return a hashmap
     */
    public static <T> Map<String, T> makeKeysLowerCase(Map<String, T> map) {
        Map<String, T> resultMap = new HashMap<String, T>();
        for (Map.Entry<String, T> entry : map.entrySet()) {
            resultMap.put(entry.getKey().toLowerCase(), entry.getValue());
        }
        return resultMap;
    }

    /**
     * Convenience function to check if a string is null or is empty
     * 
     * The str argument is trimmed before the empty check
     * 
     * @param str string to check
     * @return true if null or empty, otherwise false
     */
    public static boolean isNullOrEmpty(String str) {
        if (str == null) {
            return true;
        } else {
            return str.trim().isEmpty();
        }
    }

    /**
     * Decodes the hex string. Null if failed.
     * 
     * @param hexString string in hex format
     * @return converted ascii string
     */
    public static String decodeHex(String hexString) {
        if (hexString == null) {
            return null;
        } else {
            try {
                return new String(Hex.decodeHex(hexString.toCharArray()));
            } catch (Exception e) {
                // ignore
                return null;
            }
        }
    }

    public static boolean bigIntegerEquals(BigInteger a, BigInteger b) {
        if (a == null && b == null) {
            return true;
        } else if ((a == null && b != null) || (a != null && b == null)) {
            return false;
        } else {
            return a.equals(b);
        }
    }

    /**
     * Create hex string from ascii
     * 
     * @param string
     * @return converted hex string
     */
    public static String encodeHex(String string) {
        return Hex.encodeHexString(String.valueOf(string).getBytes());
    }

    public static void closePrintSizeAndDeleteExternalMemoryMap(String id, ExternalMemoryMap<?, ?> map) {
        if (map != null) {
            try {
                map.close();
            } catch (Exception e) {
                logger.log(Level.WARNING, id + ": Failed to close external map", e);
            }
            BigInteger sizeBytes = null;
            try {
                sizeBytes = map.getSizeOfPersistedDataInBytes();
                if (sizeBytes == null) {
                    logger.log(Level.INFO, id + ": Failed to get size of external map");
                }
            } catch (Exception e) {
                logger.log(Level.WARNING, id + ": Failed to get size of external map", e);
            }
            if (sizeBytes != null) {
                String displaySize = FileUtils.byteCountToDisplaySize(sizeBytes);
                logger.log(Level.INFO, id + ": Size of the external map on disk: {0}", displaySize);
            }
            try {
                map.delete();
            } catch (Exception e) {
                logger.log(Level.WARNING, id + ": Failed to delete external map", e);
            }
        } else {
            logger.log(Level.WARNING, id + ": NULL external map");
        }
    }

    public static <X, Y extends Serializable> ExternalMemoryMap<X, Y> createExternalMemoryMapInstance(String id,
            String cacheSizeValue, String bloomfilterFalsePositiveProbValue,
            String bloomfilterExpectedElementsCountValue, String parentDBDirPathValue, String dbDirAndNameValue,
            String reportingIntervalSecondsValue, Hasher<X> hasher) throws Exception {

        String exceptionPrefix = id + ": ExternalMemoryMap creation: ";

        if (isNullOrEmpty(id)) {
            throw new Exception(exceptionPrefix + "NULL/Empty map id: " + id + ".");
        }
        if (isNullOrEmpty(cacheSizeValue)) {
            throw new Exception(exceptionPrefix + "NULL/Empty cache size: " + cacheSizeValue + ".");
        }
        if (isNullOrEmpty(bloomfilterFalsePositiveProbValue)) {
            throw new Exception(exceptionPrefix + "NULL/Empty Bloom filter false positive probability: "
                    + bloomfilterFalsePositiveProbValue + ".");
        }
        if (isNullOrEmpty(bloomfilterExpectedElementsCountValue)) {
            throw new Exception(exceptionPrefix + "NULL/Empty Bloom filter expected number of elements: "
                    + bloomfilterExpectedElementsCountValue + ".");
        }
        if (isNullOrEmpty(parentDBDirPathValue)) {
            throw new Exception(
                    exceptionPrefix + "NULL/Empty external DB parent path: " + parentDBDirPathValue + ".");
        }
        if (isNullOrEmpty(dbDirAndNameValue)) {
            throw new Exception(exceptionPrefix + "NULL/Empty external DB name: " + dbDirAndNameValue + ".");
        }

        Integer cacheSize = CommonFunctions.parseInt(cacheSizeValue, null);
        Double falsePositiveProb = CommonFunctions.parseDouble(bloomfilterFalsePositiveProbValue, null);
        Integer expectedNumberOfElements = CommonFunctions.parseInt(bloomfilterExpectedElementsCountValue, null);
        Long reporterInterval = CommonFunctions.parseLong(reportingIntervalSecondsValue, null);

        if (cacheSize == null) {
            throw new Exception(exceptionPrefix + "Non-integer cache size: " + cacheSizeValue + ".");
        }
        if (falsePositiveProb == null) {
            throw new Exception(exceptionPrefix + "Non-double Bloom filter false positive probability: "
                    + bloomfilterFalsePositiveProbValue + ".");
        }
        if (expectedNumberOfElements == null) {
            throw new Exception(exceptionPrefix + "Non-integer Bloom filter expected number of elements: "
                    + bloomfilterExpectedElementsCountValue + ".");
        }
        if (reporterInterval == null && !isNullOrEmpty(reportingIntervalSecondsValue)) {
            throw new Exception(
                    exceptionPrefix + "Non-integer reporting interval: " + reportingIntervalSecondsValue + ".");
        }

        if (cacheSize < 1) {
            throw new Exception(exceptionPrefix + "Cache size cannot be less than 1: " + cacheSize + ".");
        }
        if (falsePositiveProb < 0 || falsePositiveProb > 1) {
            throw new Exception(exceptionPrefix + "False positive probability must be in the range [0-1]: "
                    + falsePositiveProb + ".");
        }
        if (expectedNumberOfElements < 1) {
            throw new Exception(exceptionPrefix + "Expected number of elements cannot be less than 1: "
                    + expectedNumberOfElements + ".");
        }
        if (reporterInterval != null && reporterInterval < 0) {
            throw new Exception(
                    exceptionPrefix + "Reporting interval cannot be less than 0: " + reporterInterval + ".");
        }
        if (dbDirAndNameValue.contains(File.separator)) {
            throw new Exception(exceptionPrefix + "Invalid '" + File.separator + "' character in external DB name: "
                    + dbDirAndNameValue + ".");
        }

        try {
            if (!FileUtility.createDirectories(parentDBDirPathValue)) {
                throw new Exception("");
            }
        } catch (Exception e) {
            throw new Exception(exceptionPrefix + e.getMessage() + ". Failed to create dbs parent directory: "
                    + parentDBDirPathValue);
        }

        dbDirAndNameValue += "_" + System.currentTimeMillis();
        String dbPath = parentDBDirPathValue + File.separator + dbDirAndNameValue;

        try {
            if (FileUtility.doesPathExist(dbPath)) {
                throw new Exception("DB path already in use");
            }
        } catch (Exception e) {
            throw new Exception(
                    exceptionPrefix + e.getMessage() + ". Failed to check if db path exists: " + dbPath);
        }

        try {
            if (!FileUtility.createDirectories(dbPath)) {
                throw new Exception("");
            }
        } catch (Exception e) {
            throw new Exception(exceptionPrefix + e.getMessage() + ". Failed to create db directory: " + dbPath);
        }

        try {
            ExternalStore<Y> db = new BerkeleyDB<Y>(dbPath, dbDirAndNameValue);
            ExternalMemoryMap<X, Y> map = new ExternalMemoryMap<X, Y>(id, cacheSize, db, falsePositiveProb,
                    expectedNumberOfElements);
            if (reporterInterval != null) {
                reporterInterval *= 1000;
                map.printStats(reporterInterval);
            }
            if (hasher != null) {
                map.setKeyHashFunction(hasher);
            }
            logger.log(Level.INFO,
                    id + ": ExternalMemoryMap created with params: cache size={0}, "
                            + "db path={1}, db name={2}, false positive prob={3}, expected number of elements={4}, "
                            + "reporting interval in millis={5}",
                    new Object[] { cacheSize, dbPath, dbDirAndNameValue, falsePositiveProb,
                            expectedNumberOfElements, reporterInterval });
            return map;
        } catch (Exception e) {
            try {
                if (FileUtility.doesPathExist(dbPath)) {
                    FileUtility.deleteFile(dbPath);
                }
            } catch (Exception e2) {

            }
            throw new Exception(exceptionPrefix + "Exception: " + e.getMessage());
        }
    }

    public static List<String> mapToLines(Map<String, String> map, String keyValueSeparator) {
        if (map == null) {
            return null;
        } else {
            List<String> lines = new ArrayList<String>();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                lines.add(key + keyValueSeparator + value);
            }
            return lines;
        }
    }

    /**
     * Returns hostname gotten by executing the command 'uname -n'
     * 
     * If failed to get the hostname then error message printed and null returned.
     * If succeeded then always returns a non-null value.
     * 
     * @return null/hostname
     */
    public static String getHostNameByUname() {
        String command = "uname -n";
        try {
            Execute.Output output = Execute.getOutput(command);
            if (output.hasError()) {
                output.log();
            } else {
                List<String> stdOutLines = output.getStdOut();
                if (stdOutLines == null || stdOutLines.isEmpty()) {
                    logger.log(Level.SEVERE, "NULL/Empty '" + command + "' output.");
                } else {
                    String hostName = stdOutLines.get(0);
                    if (hostName != null) {
                        return hostName;
                    } else {
                        logger.log(Level.SEVERE, "NULL '" + command + "' output line.");
                    }
                }
            }
        } catch (Throwable e) {
            logger.log(Level.SEVERE, "Failed to execute command '" + command + "'", e);
        }
        return null;
    }
}