org.projectforge.common.NumberHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.projectforge.common.NumberHelper.java

Source

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2013 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition 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; version 3 of the License.
//
// This community edition 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 org.projectforge.common;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.log4j.Logger;
import org.projectforge.core.Configuration;
import org.projectforge.core.ConfigurationParam;
import org.projectforge.user.PFUserContext;

/**
 * Some helper methods ...
 * @author Kai Reinhard (k.reinhard@micromata.de)
 */
public class NumberHelper {
    public static final String ALLOWED_PHONE_NUMBER_CHARS = "+-/().";

    public static final int KILO_BYTES = 1024;

    public static final BigDecimal KB_BD = new BigDecimal(KILO_BYTES);

    public static final int MEGA_BYTES = KILO_BYTES * 1024;

    public static final BigDecimal MB_BD = new BigDecimal(MEGA_BYTES);

    public static final int GIGA_BYTES = MEGA_BYTES * 1024;

    public static final BigDecimal GB_BD = new BigDecimal(GIGA_BYTES);

    public static final BigDecimal TWENTY = new BigDecimal(20);

    public static final BigDecimal HUNDRED = new BigDecimal(100);

    public static final BigDecimal THOUSAND = new BigDecimal(1000);

    public static final BigDecimal THREE_THOUSAND_SIX_HUNDRED = new BigDecimal(3600);

    public static final BigDecimal MINUS_TWENTY = new BigDecimal(-20);

    public static final BigDecimal MINUS_HUNDRED = new BigDecimal(-100);

    public static final BigDecimal BILLION = new BigDecimal(1000000000);

    private static final Logger log = Logger.getLogger(NumberHelper.class);

    public static NumberFormat getCurrencyFormat(final Locale locale) {
        return getNumberFraction2Format(locale);
    }

    public static NumberFormat getNumberFraction2Format(final Locale locale) {
        final NumberFormat format = NumberFormat.getNumberInstance(locale);
        format.setMaximumFractionDigits(2);
        format.setMinimumFractionDigits(2);
        return format;
    }

    public static NumberFormat getNumberFractionFormat(final Locale locale, final int fractionDigits) {
        final NumberFormat format = NumberFormat.getNumberInstance(locale);
        format.setMaximumFractionDigits(fractionDigits);
        format.setMinimumFractionDigits(fractionDigits);
        return format;
    }

    /**
     * Pretty output of bytes, "1023 bytes", "1.1 kb", "523 kb", "1.7 Mb", "143 Gb" etc.
     * @param bytes
     * @return
     */
    public static String formatBytes(final long bytes) {
        if (bytes < KILO_BYTES) {
            return String.valueOf(bytes) + " bytes";
        }
        if (bytes < MEGA_BYTES) {
            BigDecimal no = new BigDecimal(bytes).divide(KB_BD, 1, BigDecimal.ROUND_HALF_UP);
            if (no.longValue() >= 100) {
                no = no.setScale(0, BigDecimal.ROUND_HALF_UP);
            }
            return NumberFormat.getInstance(PFUserContext.getLocale()).format(no) + " kb";
        }
        if (bytes < GIGA_BYTES) {
            BigDecimal no = new BigDecimal(bytes).divide(MB_BD, 1, BigDecimal.ROUND_HALF_UP);
            if (no.longValue() >= 100) {
                no = no.setScale(0, BigDecimal.ROUND_HALF_UP);
            }
            return NumberFormat.getInstance(PFUserContext.getLocale()).format(no) + " Mb";
        }
        BigDecimal no = new BigDecimal(bytes).divide(GB_BD, 1, BigDecimal.ROUND_HALF_UP);
        if (no.longValue() >= 100) {
            no = no.setScale(0, BigDecimal.ROUND_HALF_UP);
        }
        return NumberFormat.getInstance(PFUserContext.getLocale()).format(no) + " Gb";
    }

    /**
     * @param value
     * @return true, if value is not null and greater zero.
     */
    public static boolean greaterZero(final Integer value) {
        return value != null && value.intValue() > 0;
    }

    /**
     * @param value
     * @return true, if value is not null and greater zero.
     */
    public static boolean greaterZero(final Long value) {
        return value != null && value.intValue() > 0;
    }

    public static boolean isZeroOrNull(final Integer value) {
        return (value == null || value == 0);
    }

    public static boolean isGreaterZero(final BigDecimal value) {
        return (value != null && value.compareTo(BigDecimal.ZERO) > 0);
    }

    /**
     * @param value
     * @return true, if the given value is not null and not zero.
     */
    public static boolean isNotZero(final Integer value) {
        return !isZeroOrNull(value);
    }

    /**
     * Parses the given string as integer value.
     * @param value The string representation of the integer value to parse.
     * @return Integer value or null if an empty string was given or a syntax error occurs.
     */
    public static Integer parseInteger(String value) {
        if (value == null) {
            return null;
        }
        value = value.trim();
        if (value.length() == 0) {
            return null;
        }
        Integer result = null;
        try {
            result = new Integer(value);
        } catch (final NumberFormatException ex) {
            log.debug(ex.getMessage(), ex);
        }
        return result;
    }

    /**
     * Parses the given string as short value.
     * @param value The string representation of the short value to parse.
     * @return Short value or null if an empty string was given or a syntax error occurs.
     */
    public static Short parseShort(String value) {
        if (value == null) {
            return null;
        }
        value = value.trim();
        if (value.length() == 0) {
            return null;
        }
        Short result = null;
        try {
            result = new Short(value);
        } catch (final NumberFormatException ex) {
            log.debug(ex.getMessage(), ex);
        }
        return result;
    }

    /**
     * Catches any NumberFormatException and returns 0, otherwise the long value represented by the given value is returned.
     */
    public static long parseLong(String value) {
        if (value == null) {
            return 0;
        }
        value = value.trim();
        if (value.length() == 0) {
            return 0;
        }
        Long result = null;
        try {
            result = new Long(value);
        } catch (final NumberFormatException ex) {
            log.debug(ex.getMessage(), ex);
        }
        return result;
    }

    /**
     */
    public static BigDecimal parseBigDecimal(String value) {
        if (value == null) {
            return null;
        }
        value = value.trim();
        if (value.length() == 0) {
            return null;
        }
        BigDecimal result = null;
        try {
            if (value.indexOf(',') > 0) {
                // Replace the german decimal character by '.':
                value = value.replace(',', '.');
            }
            result = new BigDecimal(value);
        } catch (final NumberFormatException ex) {
            log.debug(ex.getMessage(), ex);
        }
        return result;
    }

    /**
     */
    public static BigDecimal parseCurrency(String value, final Locale locale) {
        if (value == null) {
            return null;
        }
        value = value.trim();
        if (value.length() == 0) {
            return null;
        }
        final NumberFormat format = getCurrencyFormat(locale);
        BigDecimal result = null;
        try {
            final Number number = format.parse(value);
            if (number != null) {
                result = new BigDecimal(number.toString());
                result = result.setScale(2, BigDecimal.ROUND_HALF_UP);
            }
        } catch (final ParseException ex) {
            log.debug(ex.getMessage(), ex);
        }
        return result;
    }

    /**
     * @param v1 null is supported.
     * @param v2 null is supported.
     * @return
     */
    public static BigDecimal add(final BigDecimal v1, final BigDecimal v2) {
        if (v1 == null) {
            if (v2 == null) {
                return BigDecimal.ZERO;
            } else {
                return v2;
            }
        } else {
            if (v2 == null) {
                return v1;
            } else {
                return v1.add(v2);
            }
        }
    }

    /**
     * Returns the given integer value as String representation.
     * @param value The integer value to convert.
     * @return The String representation or empty String, if value is null.
     */
    public static String getAsString(final Number value) {
        if (value == null) {
            return "";
        } else {
            return String.valueOf(value);
        }
    }

    /**
     * Returns the given number value as String representation.
     * @param value The number value to convert.
     * @param format The format to use.
     * @return The String representation or empty String, if value is null.
     */
    public static String getAsString(final Number value, final NumberFormat format) {
        if (value == null) {
            return "";
        } else {
            return format.format(value);
        }
    }

    /**
     * @see PFUserContext#getLocale()
     */
    public static String formatFraction2(final Number value) {
        final Locale locale = PFUserContext.getLocale();
        final NumberFormat format = getNumberFraction2Format(locale);
        return format.format(value);
    }

    /**
     * Uses the default country phone prefix from the configuration.
     * @see #extractPhonenumber(String, String)
     */
    public static String extractPhonenumber(final String str) {
        final String defaultCountryPhonePrefix = Configuration.getInstance()
                .getStringValue(ConfigurationParam.DEFAULT_COUNTRY_PHONE_PREFIX);

        return extractPhonenumber(str, defaultCountryPhonePrefix);
    }

    /**
     * Extracts the phone number of the given string. All characters of the set "+-/()." and white spaces will be deleted and +## will be
     * replaced by 00##. Example: +49 561 / 316793-0 -> 00495613167930 <br/>
     * Ignores any characters after the first occurence of ':' or any letter.
     * @param str
     * @param countryPrefix If country prefix is given, for all numbers beginning with the country prefix the country prefix will be replaced
     *          by 0. Example: ("+49 561 / 316793-0", "+49") -> 05613167930; ("+39 123456", "+49") -> 0039123456.
     * @return
     */
    public static String extractPhonenumber(String str, final String countryPrefix) {
        if (str == null) {
            return null;
        }
        str = str.trim();
        final StringBuffer buf = new StringBuffer();
        if (StringUtils.isNotEmpty(countryPrefix) == true && str.startsWith(countryPrefix) == true) {
            buf.append('0');
            str = str.substring(countryPrefix.length());
        } else if (str.length() > 3 && str.charAt(0) == '+' && Character.isDigit(str.charAt(1)) == true
                && Character.isDigit(str.charAt(2)) == true) {
            buf.append("00");
            buf.append(str.charAt(1));
            buf.append(str.charAt(2));
            str = str.substring(3);
        }
        for (int i = 0; i < str.length(); i++) {
            final char ch = str.charAt(i);
            if (Character.isDigit(str.charAt(i)) == true) {
                buf.append(ch);
            } else if (Character.isWhitespace(ch) == true) {
                // continue.
            } else if (ALLOWED_PHONE_NUMBER_CHARS.indexOf(ch) < 0) {
                break;
            }
        }
        return buf.toString();
    }

    /**
     * Compares two given BigDecimals. They are equal if the value is equal independent of the scale (5.70 is equals to 5.7 and null is equals
     * null, but null is not equals to 0).
     * @param value1
     * @param value2
     * @return
     * @see BigDecimal#compareTo(BigDecimal)
     */
    public static boolean isEqual(final BigDecimal value1, final BigDecimal value2) {
        if (value1 == null) {
            return (value2 == null) ? true : false;
        }
        if (value2 == null) {
            return false;
        }
        return value1.compareTo(value2) == 0;
    }

    /**
     * @param value
     * @return true, if the given value is not null and not zero.
     */
    public static boolean isNotZero(final BigDecimal value) {
        return !isZeroOrNull(value);
    }

    public static boolean isZeroOrNull(final BigDecimal value) {
        return (value == null || value.compareTo(BigDecimal.ZERO) == 0);
    }

    /**
     * Compares two given Integers using compareTo method.
     * @param value1
     * @param value
     * @return
     * @see Integer#compareTo(Integer)
     */
    public static boolean isEqual(final Integer value1, final Integer value) {
        if (value1 == null) {
            return (value == null) ? true : false;
        }
        if (value == null) {
            return false;
        }
        return value1.compareTo(value) == 0;
    }

    /**
     * Splits string representation of the given number into digits. Examples:<br/>
     * NumberHelper.splitToInts(11110511, 1, 3, 2, 2) = {1, 111, 5, 11}<br/>
     * NumberHelper.splitToInts(10000511, 1, 3, 2, 2) = { 1, 0, 5, 11}<br/>
     * NumberHelper.splitToInts(511, 1, 3, 2, 2) = { 0, 0, 5, 11}
     * @param value
     * @param split
     * @return
     */
    public static int[] splitToInts(final Number value, final int... split) {
        int numberOfDigits = 0;
        for (final int n : split) {
            numberOfDigits += n;
        }
        final String str = StringUtils.leftPad(String.valueOf(value.intValue()), numberOfDigits, '0');
        final int[] result = new int[split.length];
        int pos = 0;
        int i = 0;
        for (final int n : split) {
            result[i++] = parseInteger(str.substring(pos, pos + n));
            pos += n;
        }
        return result;
    }

    /**
     * If given string is an number (NumberUtils.isNumber(String)) then it will be converted to a plain string via BigDecimal.toPlainString().
     * Any exponent such as 1E7 will be avoided.
     * @param str
     * @return Converted string if number, otherwise the origin string.
     * @see NumberUtils#isNumber(String)
     * @see NumberUtils#createBigDecimal(String)
     * @see BigDecimal#toPlainString()
     */
    public static String toPlainString(final String str) {
        if (NumberUtils.isNumber(str) == true) {
            final BigDecimal bd = NumberUtils.createBigDecimal(str);
            return bd.toPlainString();
        } else {
            return str;
        }
    }

    /**
     * Sets scale 0 for numbers greater 100, 1 for numbers greater 20 and 2 as default.
     * @param number
     * @return
     */
    public static BigDecimal setDefaultScale(final BigDecimal number) {
        if (number == null) {
            return null;
        }
        if (number.compareTo(NumberHelper.HUNDRED) >= 0 || number.compareTo(NumberHelper.MINUS_HUNDRED) <= 0) {
            return number.setScale(0, BigDecimal.ROUND_HALF_UP);
        } else if (number.compareTo(NumberHelper.TWENTY) >= 0 || number.compareTo(NumberHelper.MINUS_TWENTY) <= 0) {
            return number.setScale(1, BigDecimal.ROUND_HALF_UP);
        }
        return number.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * Generates secure random bytes of the given length and return base 64 encoded bytes as url safe String. This is not the length of the
     * resulting string!
     * @param numberOfBytes
     * @return
     */
    public static String getSecureRandomUrlSaveString(final int numberOfBytes) {
        final SecureRandom random = new SecureRandom();
        final byte[] bytes = new byte[numberOfBytes];
        random.nextBytes(bytes);
        return Base64.encodeBase64URLSafeString(bytes);
    }

    public static boolean isIn(final int value, final int... numbers) {
        if (numbers == null) {
            return false;
        }
        for (final int number : numbers) {
            if (value == number) {
                return true;
            }
        }
        return false;
    }
}