net.sf.jasperreports.functions.standard.MathFunctions.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jasperreports.functions.standard.MathFunctions.java

Source

/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.jasperreports.functions.standard;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.jasperreports.functions.annotations.Function;
import net.sf.jasperreports.functions.annotations.FunctionCategories;
import net.sf.jasperreports.functions.annotations.FunctionParameter;
import net.sf.jasperreports.functions.annotations.FunctionParameters;

/**
 * This class should maintain all function methods that belongs to the Math category.
 * 
 * @author Massimo Rabbi (mrabbi@users.sourceforge.net)
 */
@FunctionCategories({ MathCategory.class })
public final class MathFunctions {
    private static final Log log = LogFactory.getLog(MathFunctions.class);

    // ===================== ABS function ===================== //
    /**
     * Returns the absolute value of a number.
     */
    @Function("ABS")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Number ABS(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        } else {
            if (number instanceof Integer) {
                return Math.abs((Integer) number);
            } else if (number instanceof Double) {
                return Math.abs((Double) number);
            } else if (number instanceof Float) {
                return Math.abs((Float) number);
            } else if (number instanceof Long) {
                return Math.abs((Long) number);
            } else {
                // fall-back
                return Math.abs(number.doubleValue());
            }
        }
    }

    // ===================== FACT function ===================== //
    /**
     * Returns the factorial of a number.
     */
    @Function("FACT")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Long FACT(Integer number) {
        if (number == null) {
            logNullArgument();
            return null;
        }
        if (number < 0) {
            if (log.isDebugEnabled()) {
                log.debug("Unable to calculate the factorial number of a negative number.");
            }
            return null;
        } else {
            Long result = 1l;
            for (int i = 1; i <= number; ++i) {
                result *= i;
            }
            return result;
        }
    }

    // ===================== ISEVEN function ===================== //
    /**
     * Checks if a number is even. If a non-integer number is specified, any digits after the decimal point are ignored.
     */
    @Function("ISEVEN")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Boolean ISEVEN(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        } else {
            return number.intValue() % 2 == 0;
        }
    }

    // ===================== ISODD function ===================== //
    /**
     * Checks if a number is odd. If a non-integer number is specified, any digits after the decimal point are ignored.
     */
    @Function("ISODD")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Boolean ISODD(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        } else {
            return number.intValue() % 2 == 1;
        }
    }

    // ===================== PRODUCT function ===================== //
    /**
     * Returns the product of a list of numbers.
     */
    @Function("PRODUCT")
    @FunctionParameters({ @FunctionParameter("numbers") })
    public static Number PRODUCT(Number... numbers) {
        if (numbers.length == 0) {
            logEmptyArgumentsList();
            return null;
        }
        if (!isNumberListValid(numbers)) {
            logArgumentsWithNullElements();
            return null;
        }
        double result = 1;
        for (int i = 0; i < numbers.length; i++) {
            result *= numbers[i].doubleValue();
        }
        return result;
    }

    // ===================== RAND function ===================== //
    /**
     * Returns a random number between 0.0 and 1.0.
     */
    @Function("RAND")
    public static Double RAND() {
        return Math.random();
    }

    // ===================== RAND function ===================== //
    /**
     * Returns an Integer random number between bottom and top range (both inclusive).
     */
    @Function("RANDBETWEEN")
    @FunctionParameters({ @FunctionParameter("bottomRange"), @FunctionParameter("topRange") })
    public static Integer RANDBETWEEN(Integer bottomRange, Integer topRange) {
        int min = bottomRange;
        int max = topRange;
        return min + (int) (Math.random() * ((max - min) + 1));
    }

    // ===================== SIGN function ===================== //
    /**
     * Returns the sign of a number.
     */
    @Function("SIGN")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Integer SIGN(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        } else {
            return (int) Math.signum(number.doubleValue());
        }
    }

    // ===================== SQRT function ===================== //
    /**
     * Returns the positive square root of a number. The number must be positive.
     */
    @Function("SQRT")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Number SQRT(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        } else {
            return Math.sqrt(number.doubleValue());
        }
    }

    // ===================== SUM function ===================== //
    /**
     * Returns the sum of a list of numbers.
     */
    @Function("SUM")
    @FunctionParameters({ @FunctionParameter("numbers") })
    public static Number SUM(Number... numbers) {
        if (numbers.length == 0) {
            logEmptyArgumentsList();
            return null;
        }
        if (!isNumberListValid(numbers)) {
            logArgumentsWithNullElements();
            return null;
        }
        double result = 0;
        for (int i = 0; i < numbers.length; i++) {
            result += numbers[i].doubleValue();
        }
        return result;
    }

    // ===================== MIN function ===================== //
    /**
     * Returns the minimum of a list of numeric values.
     */
    @Function("MIN")
    @FunctionParameters({ @FunctionParameter("numbers") })
    public static Number MIN(Number... numbers) {
        if (numbers.length == 0) {
            logEmptyArgumentsList();
            return null;
        }
        if (!isNumberListValid(numbers)) {
            logArgumentsWithNullElements();
            return null;
        }
        double min = numbers[0].doubleValue();
        for (int i = 1; i < numbers.length; i++) {
            if (numbers[i].doubleValue() < min) {
                min = numbers[i].doubleValue();
            }
        }
        return fixNumberReturnType(min, numbers);
    }

    // ===================== MAX function ===================== //
    /**
     * Returns the maximum of a list of numeric values.
     */
    @Function("MAX")
    @FunctionParameters({ @FunctionParameter("numbers") })
    public static Number MAX(Number... numbers) {
        if (numbers.length == 0) {
            logEmptyArgumentsList();
            return null;
        }
        if (!isNumberListValid(numbers)) {
            logArgumentsWithNullElements();
            return null;
        }
        double max = numbers[0].doubleValue();
        for (int i = 1; i < numbers.length; i++) {
            if (numbers[i].doubleValue() > max) {
                max = numbers[i].doubleValue();
            }
        }
        return fixNumberReturnType(max, numbers);
    }

    // ===================== FLOOR function ===================== //
    /**
     * Returns the largest (closest to positive infinity) double value that is less than or equal to the argument and is equal to a mathematical integer.
     */
    @Function("FLOOR")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Double FLOOR(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        }
        return Math.floor(number.doubleValue());
    }

    // ===================== CEIL function ===================== //
    /**
     * Returns the smallest (closest to negative infinity) double value that is greater than or equal to the argument and is equal to a mathematical integer
     */
    @Function("CEIL")
    @FunctionParameters({ @FunctionParameter("number") })
    public static Double CEIL(Number number) {
        if (number == null) {
            logNullArgument();
            return null;
        }
        return Math.ceil(number.doubleValue());
    }

    /*
     * Checks if the array of numbers is valid. 
     * No null element must be contained.
     */
    private static boolean isNumberListValid(Number... numbers) {
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == null)
                return false;
        }
        return true;
    }

    /*
     * Fixes the return type for the numeric result value.
     */
    private static Number fixNumberReturnType(Number returnValue, Number... numbers) {
        if (haveSameType(Integer.class, numbers))
            return returnValue.intValue();
        if (haveSameType(Long.class, numbers))
            return returnValue.longValue();
        if (haveSameType(Float.class, numbers))
            return returnValue.floatValue();
        return returnValue.doubleValue();
    }

    /*
     * Checks if the list of generic numbers have all the same type.
     */
    private static boolean haveSameType(Class<? extends Number> clazz, Number... numbers) {
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i].getClass() != clazz) {
                return false;
            }
        }
        return true;
    }

    /* Utility methods for logging common messages */

    private static void logNullArgument() {
        if (log.isDebugEnabled()) {
            log.debug("The argument can not be null.");
        }
    }

    private static void logEmptyArgumentsList() {
        if (log.isDebugEnabled()) {
            log.debug("No arguments were specified.");
        }
    }

    private static void logArgumentsWithNullElements() {
        if (log.isDebugEnabled()) {
            log.debug("No null element is allowed among arguments");
        }
    }

}