ru.runa.wfe.extension.handler.var.FormulaActionHandlerOperations.java Source code

Java tutorial

Introduction

Here is the source code for ru.runa.wfe.extension.handler.var.FormulaActionHandlerOperations.java

Source

/*
 * This file is part of the RUNA WFE project.
 *
 * This program 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; version 2.1
 * of the License.
 *
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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 ru.runa.wfe.extension.handler.var;

import java.io.InputStream;
import java.math.BigDecimal;
import java.math.MathContext;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;

import ru.runa.wfe.commons.CalendarUtil;
import ru.runa.wfe.commons.ClassLoaderUtil;
import ru.runa.wfe.commons.TypeConversionUtil;
import ru.runa.wfe.commons.xml.XmlUtils;
import ru.runa.wfe.extension.function.CreateSubListByIndexes;
import ru.runa.wfe.extension.function.DeleteListElementsByIndexes;
import ru.runa.wfe.extension.function.Function;
import ru.runa.wfe.extension.function.GetListMatchedIndexes;
import ru.runa.wfe.extension.function.GetListMismatchedIndexes;
import ru.runa.wfe.extension.function.GetSize;
import ru.runa.wfe.extension.function.ListToString;
import ru.runa.wfe.extension.function.ToList;

import com.google.common.collect.Maps;

public class FormulaActionHandlerOperations {
    private static final Log log = LogFactory.getLog(FormulaActionHandlerOperations.class);
    private static final Map<String, Function<? extends Object>> functions = Maps.newHashMap();
    private static TreeMap<String, HashMap<Integer, String>> names = new TreeMap<String, HashMap<Integer, String>>();
    private static TreeMap<String, HashMap<Integer, String>> families = new TreeMap<String, HashMap<Integer, String>>();
    private static TreeMap<String, HashMap<Integer, String>> parents = new TreeMap<String, HashMap<Integer, String>>();
    private static TreeMap<String, HashMap<String, String>> mappingConf = new TreeMap<String, HashMap<String, String>>();
    static {
        registerFunction(new ListToString());
        registerFunction(new GetListMatchedIndexes());
        registerFunction(new GetListMismatchedIndexes());
        registerFunction(new CreateSubListByIndexes());
        registerFunction(new DeleteListElementsByIndexes());
        registerFunction(new ToList());
        registerFunction(new GetSize());
        //
        readNameCaseConfig("nameCaseConf.xml");
        readMappingConfig("mappingConf.xml");
    }

    public static Function<? extends Object> getFunction(String name) {
        return functions.get(name);
    }

    private static void readNameCaseConfig(String path) {
        try {
            InputStream is = ClassLoaderUtil.getAsStream(path, FormulaActionHandlerOperations.class);
            if (is == null) {
                log.warn("No " + path + " found");
                return;
            }
            Document document = XmlUtils.parseWithoutValidation(is);
            @SuppressWarnings("unchecked")
            List<Element> childs = document.getRootElement().elements();
            for (Element element : childs) {
                if (element.getName().equals("name")) {
                    names.put(element.attributeValue("value"), parseNameCaseRules(element));
                }
                if (element.getName().equals("family")) {
                    families.put(element.attributeValue("value"), parseNameCaseRules(element));
                }
                if (element.getName().equals("parent")) {
                    parents.put(element.attributeValue("value"), parseNameCaseRules(element));
                }
            }
        } catch (Exception e) {
            log.error("Can`t parse " + path, e);
        }
    }

    private static HashMap<Integer, String> parseNameCaseRules(Element element) {
        HashMap<Integer, String> result = new HashMap<Integer, String>();
        @SuppressWarnings("unchecked")
        List<Element> childs = element.elements();
        for (Element child : childs) {
            if (child.getName().equals("name")) {
                break;
            }
            int c = Integer.parseInt(child.attributeValue("case"));
            result.put(c, child.getText());
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    private static void readMappingConfig(String path) {
        try {
            InputStream is = ClassLoaderUtil.getAsStream(path, FormulaActionHandlerOperations.class);
            if (is == null) {
                log.warn("No " + path + " found");
                return;
            }
            Document document = XmlUtils.parseWithoutValidation(is);
            List<Element> childs = document.getRootElement().elements();
            for (Element rule : childs) {
                String title = rule.attributeValue("title");
                HashMap<String, String> rmap = new HashMap<String, String>();
                for (Element item : (List<Element>) rule.elements()) {
                    String input = item.attributeValue("input");
                    String output = item.attributeValue("output");
                    rmap.put(input, output);
                }
                mappingConf.put(title, rmap);
            }
        } catch (Exception e) {
            log.error("Can`t parse " + path, e);
        }
    }

    private static void registerFunction(Function<? extends Object> function) {
        functions.put(function.getName(), function);
    }

    public Object sum(Object o1, Object o2) {
        if (BigDecimal.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return ((BigDecimal) o1).add(asBigDecimal((Number) o2));
        }
        if (Number.class.isInstance(o1) && BigDecimal.class.isInstance(o2)) {
            return asBigDecimal((Number) o1).add((BigDecimal) o2);
        }
        if (Double.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Double(((Number) o1).doubleValue() + ((Number) o2).doubleValue());
        }
        if (Number.class.isInstance(o1) && Double.class.isInstance(o2)) {
            return new Double(((Number) o1).doubleValue() + ((Number) o2).doubleValue());
        }
        if (Long.class.isInstance(o1) && Long.class.isInstance(o2)) {
            return new Long((long) (((Long) o1).doubleValue() + ((Long) o2).doubleValue()));
        }
        if (Date.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Date(((Date) o1).getTime() + (long) (((Number) o2).doubleValue() * 60 * 1000));
        }
        if (Date.class.isInstance(o1) && Date.class.isInstance(o2)) {
            Date date2 = (Date) o2;
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date2);
            return new Date(((Date) o1).getTime() + calendar.get(Calendar.HOUR_OF_DAY) * 3600000
                    + calendar.get(Calendar.MINUTE) * 60000);
        }
        if (String.class.isInstance(o1)) {
            return (String) o1 + translate(o2, String.class);
        }
        if (String.class.isInstance(o2)) {
            return translate(o1, String.class).toString() + (String) o2;
        }
        log.error("Cannot make summation for " + (o1 != null ? o1.getClass() : "null") + " with "
                + (o2 != null ? o2.getClass() : "null"));
        return null;
    }

    public Object sub(Object o1, Object o2) {
        if (BigDecimal.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return ((BigDecimal) o1).subtract(asBigDecimal((Number) o2));
        }
        if (Number.class.isInstance(o1) && BigDecimal.class.isInstance(o2)) {
            return asBigDecimal((Number) o1).subtract((BigDecimal) o2);
        }
        if (Double.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Double(((Number) o1).doubleValue() - ((Number) o2).doubleValue());
        }
        if (Number.class.isInstance(o1) && Double.class.isInstance(o2)) {
            return new Double(((Number) o1).doubleValue() - ((Number) o2).doubleValue());
        }
        if (Long.class.isInstance(o1) && Long.class.isInstance(o2)) {
            return new Long((long) (((Number) o1).doubleValue() - ((Number) o2).doubleValue()));
        }
        if (Date.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Date(((Date) o1).getTime() - (long) (((Number) o2).doubleValue() * 60 * 1000));
        }
        if (Date.class.isInstance(o1) && Date.class.isInstance(o2)) {
            return new Long((((Date) o1).getTime() - ((Date) o2).getTime()) / 60000);
        }
        log.error("Cannot make substraction for " + o1.getClass() + " with " + o2.getClass());
        return null;
    }

    public Object mul(Object o1, Object o2) {
        if (BigDecimal.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return ((BigDecimal) o1).multiply(asBigDecimal((Number) o2));
        }
        if (Number.class.isInstance(o1) && BigDecimal.class.isInstance(o2)) {
            return asBigDecimal((Number) o1).multiply((BigDecimal) o2);
        }
        if (Double.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Double(((Number) o1).doubleValue() * ((Number) o2).doubleValue());
        }
        if (Number.class.isInstance(o1) && Double.class.isInstance(o2)) {
            return new Double(((Number) o1).doubleValue() * ((Number) o2).doubleValue());
        }
        if (Long.class.isInstance(o1) && Long.class.isInstance(o2)) {
            return new Long((long) (((Number) o1).doubleValue() * ((Number) o2).doubleValue()));
        }
        log.error("Cannot make multiplication for " + (o1 != null ? o1.getClass() : "null") + " with "
                + (o2 != null ? o2.getClass() : "null"));
        return null;
    }

    public Object div(Object o1, Object o2) {
        if (BigDecimal.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return ((BigDecimal) o1).divide(asBigDecimal((Number) o2), MathContext.DECIMAL128);
        }
        if (Number.class.isInstance(o1) && BigDecimal.class.isInstance(o2)) {
            return asBigDecimal((Number) o1).divide((BigDecimal) o2, MathContext.DECIMAL128);
        }
        if (Double.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Double(((Double) o1).doubleValue() / ((Number) o2).doubleValue());
        }
        if (Long.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return new Long((long) (((Long) o1).doubleValue() / ((Number) o2).doubleValue()));
        }
        log.error("Cannot make division for " + o1.getClass() + " with " + o2.getClass());
        return null;
    }

    public Object changeSign(Object o) {
        if (BigDecimal.class.isInstance(o)) {
            return ((BigDecimal) o).negate();
        }
        if (Double.class.isInstance(o)) {
            return new Double(-((Double) o).doubleValue());
        }
        if (Long.class.isInstance(o)) {
            return new Long(-((Long) o).longValue());
        }
        log.error("Cannot make changeSign for " + o.getClass());
        return null;
    }

    public Object not(Object o) {
        if (Boolean.class.isInstance(o)) {
            return new Boolean(!((Boolean) o).booleanValue());
        }
        log.error("Cannot make not for " + o.getClass());
        return null;
    }

    public Object less(Object o1, Object o2) {
        if (BigDecimal.class.isInstance(o1) && Number.class.isInstance(o2)) {
            return ((BigDecimal) o1).compareTo(asBigDecimal((Number) o2)) < 0;
        }
        if (Number.class.isInstance(o1) && BigDecimal.class.isInstance(o2)) {
            return asBigDecimal((Number) o1).compareTo((BigDecimal) o2) < 0;
        }
        if (Double.class.isInstance(o1) && Double.class.isInstance(o2)) {
            return new Boolean(((Double) o1).doubleValue() < ((Double) o2).doubleValue());
        }
        if (Double.class.isInstance(o1) && Long.class.isInstance(o2)) {
            return new Boolean(((Double) o1).doubleValue() < ((Long) o2).doubleValue());
        }
        if (Long.class.isInstance(o1) && Double.class.isInstance(o2)) {
            return new Boolean(((Long) o1).doubleValue() < ((Double) o2).doubleValue());
        }
        if (Long.class.isInstance(o1) && Long.class.isInstance(o2)) {
            return new Boolean(((Long) o1).longValue() < ((Long) o2).longValue());
        }
        if (String.class.isInstance(o1) && String.class.isInstance(o2)) {
            return new Boolean(((String) o1).compareTo((String) o2) < 0);
        }
        if (Date.class.isInstance(o1) && Date.class.isInstance(o2)) {
            return new Boolean(((Date) o1).compareTo((Date) o2) < 0);
        }
        log.error("Cannot make less for " + o1.getClass() + " with " + o2.getClass());
        return null;
    }

    public Object bigger(Object o1, Object o2) {
        return less(o2, o1);
    }

    public Object equal(Object o1, Object o2) {
        if (BigDecimal.class.isInstance(o1) && BigDecimal.class.isInstance(o2)) {
            return new Boolean(((BigDecimal) o1).compareTo((BigDecimal) o2) == 0);
        }
        return new Boolean(o1.equals(o2));
    }

    public Object lessOrEqual(Object o1, Object o2) {
        Object less = less(o1, o2);
        Object equal = equal(o1, o2);
        return or(less, equal);
    }

    public Object biggerOrEqual(Object o1, Object o2) {
        Object bigger = bigger(o1, o2);
        Object equal = equal(o1, o2);
        return or(bigger, equal);
    }

    public Object or(Object o1, Object o2) {
        if (Boolean.class.isInstance(o1) && Boolean.class.isInstance(o2)) {
            return new Boolean(((Boolean) o1).booleanValue() || ((Boolean) o2).booleanValue());
        }
        log.error("Cannot make or for " + o1.getClass() + " with " + o2.getClass());
        return null;
    }

    public Object and(Object o1, Object o2) {
        if (Boolean.class.isInstance(o1) && Boolean.class.isInstance(o2)) {
            return new Boolean(((Boolean) o1).booleanValue() && ((Boolean) o2).booleanValue());
        }
        log.error("Cannot make and for " + o1.getClass() + " with " + o2.getClass());
        return null;
    }

    public Object xor(Object o1, Object o2) {
        if (Boolean.class.isInstance(o1) && Boolean.class.isInstance(o2)) {
            return new Boolean(((Boolean) o1).booleanValue() ^ ((Boolean) o2).booleanValue());
        }
        log.error("Cannot make xor for " + o1.getClass() + " with " + o2.getClass());
        return null;
    }

    public Object translate(Object o, Class<?> c) {
        if (c == String.class && Date.class.isInstance(o)) {
            Date date = (Date) o;
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date);
            if (calendar.get(Calendar.YEAR) == 1970 && calendar.get(Calendar.MONTH) == Calendar.JANUARY
                    && calendar.get(Calendar.DAY_OF_MONTH) == 1) {
                return CalendarUtil.format(date, CalendarUtil.HOURS_MINUTES_FORMAT);
            }
            if (calendar.get(Calendar.HOUR) == 0 && calendar.get(Calendar.MINUTE) == 0
                    && calendar.get(Calendar.SECOND) == 0) {
                return CalendarUtil.format(date, CalendarUtil.DATE_WITHOUT_TIME_FORMAT);
            }
            return CalendarUtil.format(date, CalendarUtil.DATE_WITH_HOUR_MINUTES_FORMAT);
        }
        if (Date.class.isAssignableFrom(c) && Date.class.isInstance(o)) {
            return o;
        }
        return TypeConversionUtil.convertTo(c, o);
    }

    public Object dateFunction(Object p) {
        if (!Date.class.isInstance(p)) {
            return null;
        }
        Date d = (Date) p;
        try {
            return new SimpleDateFormat("dd.MM.yy").parse(new SimpleDateFormat("dd.MM.yy").format(d));
        } catch (ParseException e) {
            log.warn("Unparseable date", e);
        }
        return null;
    }

    public Object timeFunction(Object p) {
        if (!Date.class.isInstance(p)) {
            return null;
        }
        Date d = (Date) p;
        try {
            String s = CalendarUtil.format(d, CalendarUtil.HOURS_MINUTES_FORMAT);
            return CalendarUtil.convertToDate(s, CalendarUtil.HOURS_MINUTES_FORMAT);
        } catch (Exception e) {
            log.warn("Unparseable time", e);
        }
        return null;
    }

    public Object hoursRoundUpFunction(Object p) {
        Double d = (Double) translate(p, Double.class);
        if (d == null) {
            return null;
        }
        double minutes = d.doubleValue();
        long hours = (long) (minutes / 60);
        if (hours * 60 < minutes) {
            hours++;
        }
        return new Long(hours * 60);
    }

    public Long roundUpFunction(double d) {
        return (long) d + (d == (long) d ? 0 : 1);
    }

    public Long roundDownFunction(double d) {
        return (long) d;
    }

    public Long roundFunction(double d) {
        return Math.round(d);
    }

    public Double roundUpFunction(double d, int num) {
        long st = 1;
        while (num-- > 0) {
            st *= 10;
        }
        return (double) roundUpFunction(d * st) / st;
    }

    public Double roundDownFunction(double d, int num) {
        long st = 1;
        while (num-- > 0) {
            st *= 10;
        }
        return (double) roundDownFunction(d * st) / st;
    }

    public Double roundFunction(double d, int num) {
        long st = 1;
        while (num-- > 0) {
            st *= 10;
        }
        return (double) roundFunction(d * st) / st;
    }

    public String mapping(String input, String rule) {
        try {
            return mappingConf.get(rule).get(input);
        } catch (Exception e) {
            log.error("No mapping rule for " + input + " / " + rule, e);
        }
        return input;
    }

public String nameCaseRussian(String fio, int caseNumber, String mode) {
    boolean sex = false;
    StringTokenizer st = new StringTokenizer(fio);
    if (st.hasMoreElements()) {
        st.nextToken();
    }
    if (st.hasMoreElements()) {
        st.nextToken();
    }
    String parent = st.hasMoreElements() ? st.nextToken() : "   ";
    if (parent.charAt(parent.length() - 1) == '') {
        sex = true;
    }
    return nameCaseRussian(fio, caseNumber, sex, mode);
}

    public String nameCaseRussian(String fio, int caseNumber, boolean sex, String mode) {
        StringTokenizer st = new StringTokenizer(fio);
        String family = st.hasMoreElements() ? st.nextToken() : "";
        String name = st.hasMoreElements() ? st.nextToken() : "";
        String parent = st.hasMoreElements() ? st.nextToken() : "";

        String answer = "";
        for (char c : mode.toCharArray()) {
            switch (c) {
            case 'F':
                answer += wordCaseRussian(family, caseNumber, sex, 1, false);
                break;
            case 'I':
                answer += wordCaseRussian(name, caseNumber, sex, 2, false);
                break;
            case 'O':
                answer += wordCaseRussian(parent, caseNumber, sex, 3, false);
                break;
            case 'f':
                answer += wordCaseRussian(family, caseNumber, sex, 1, true);
                break;
            case 'i':
                answer += wordCaseRussian(name, caseNumber, sex, 2, true);
                break;
            case 'o':
                answer += wordCaseRussian(parent, caseNumber, sex, 3, true);
                break;
            default:
                answer += c;
            }
        }

        return answer;
    }

    private String wordCaseRussian(String word, int caseNumber, boolean sex, int wordType, boolean onlyOneChar) {
        // sex : male = true, female = false
        // wordType : 1 = family name, 2 = name, 3 = parent

        // http://sourceforge.net/p/runawfe/bugs/624/
        if (word == null || word.length() == 0) {
            return "";
        }

        if (onlyOneChar) {
            return "" + Character.toUpperCase(word.replaceAll(" ", "").charAt(0)) + '.';
        }

        switch (wordType) {
        case 1:
            if (families.containsKey(word) && families.get(word).containsKey(caseNumber)) {
                return families.get(word).get(caseNumber);
            }
            break;
        case 2:
            if (names.containsKey(word) && names.get(word).containsKey(caseNumber)) {
                return names.get(word).get(caseNumber);
            }
            break;
        case 3:
            if (parents.containsKey(word) && parents.get(word).containsKey(caseNumber)) {
                return parents.get(word).get(caseNumber);
            }
            break;
        }

        int i = word.indexOf("-");
        if (i > 0) {
            String part1 = word.substring(0, i);
            String part2 = word.substring(i + 1);
            return wordCaseRussian(part1, caseNumber, sex, wordType, onlyOneChar) + "-"
                    + wordCaseRussian(part2, caseNumber, sex, wordType, onlyOneChar);
        }

        int len = word.length();
        word = word.toLowerCase();

        String suf3 = word.length() >= 3 ? word.substring(len - 3, len) : "___";
        String suf2 = word.length() >= 2 ? word.substring(len - 2, len) : "__";
        String suf1 = word.length() >= 1 ? word.substring(len - 1, len) : "_";

        if (suf3.equals("") && wordType == 1 && !onlyOneChar && word.length() > 4) {
            String prefix = upcaseFirstChar(word.substring(0, len - 3));
            switch (caseNumber) {
            case 1:
                return prefix + "";
            case 2:
                return prefix + "";
            case 3:
                return prefix + "";
            case 4:
                return prefix + "";
            case 5:
                return prefix + "";
            case 6:
                return prefix + "";
            }
        }

        int za = "? ?   ?         ".indexOf(suf2) + 1;
        int zb = "??".indexOf(suf3.charAt(0)) + 1;
        int zd = 5;
        if (za != 4) {
            zd = "?".indexOf(suf1) + 1;
        }
        String fs1 = "" + (sex ? "" : "?");
        String fs2 = "? ?? ? ? ? ?";
        boolean b = caseNumber == 1 || suf1.equals(".") || wordType == 2 && fs1.indexOf(suf1) >= 0
                || wordType == 1 && fs2.indexOf(suf3) >= 0;
        if (b) {
            zd = 9;
        } else {
            boolean b2 = zd == 4 && sex;
            if (b2) {
                zd = 2;
            } else {
                if (wordType == 1) {
                    if ("".indexOf(suf1)
                            + "         ?  ?".indexOf(suf2) + 2 > 0) {
                        zd = 9;
                    } else {
                        if (!sex) {
                            if (za == 1) {
                                zd = 7;
                            } else {
                                if (suf1.equals("")) {
                                    zd = za > 18 ? 1 : 6;
                                } else {
                                    zd = 9;
                                }
                            }
                        } else {
                            boolean b3 = " ".indexOf(suf2) >= 0 && wordType > 4
                                    && !word.substring(len - 4, len).equals("") || zb > 10 && za > 16;
                            if (b3) {
                                zd = 8;
                            }
                        }
                    }
                }
            }
        }

        int ze = "            "
                .indexOf(suf3) + 1;

        String zf = zd == 8 && caseNumber != 5 ? zb > 15 || " ".indexOf(suf3) >= 0 ? "" : ""
                : word.equals("") ? ""
                        : len - 4 >= 0 && "??".indexOf(word.substring(len - 4, len - 3)) < 0
                                && (zb > 11 || zb == 0) && ze != 45
                                        ? ""
                                        : za == 7 ? ""
                                                : za == 10 ? ""
                                                        : za == 13 ? ""
                                                                : ze == 0 ? ""
                                                                        : ze < 12 ? "" + (ze == 1 ? "" : "")
                                                                                : ze < 37 ? ""
                                                                                        : ze < 49 ? "" : "";

        if (zd != 9) {
            int nm = len;
            if (zd > 6 || zf.length() > 0) {
                nm -= 2;
            } else {
                nm -= zd > 0 ? 1 : 0;
            }
            String ns = word.substring(0, nm);
            ns += zf;
            String ss = "   " + "".substring("".indexOf(suf1) + 1).charAt(0) + " "
                    + ("".indexOf(suf2.charAt(0)) > 0 ? "" : "") + "    ?  ? "
                    + (za == 16 ? "" : "")
                    + "              "
                    + (zf.equals("") || za == 16 || zb > 12 && zb < 16 ? "" : "") + "";
            ns += ss.substring(10 * zd + 2 * caseNumber - 3 - 1, 10 * zd + 2 * caseNumber - 3 + 1);
            zf = ns;
        } else {
            zf = word;
        }

        String ans = zf;
        ans = ans.replace(" ", "");
        ans = upcaseFirstChar(ans);
        return ans;
    }

    private String upcaseFirstChar(String ans) {
        if (ans.length() != 0) {
            ans = "" + Character.toUpperCase(ans.charAt(0)) + ans.substring(1);
        }
        return ans;
    }

    private BigDecimal asBigDecimal(Number n) {
        if (BigDecimal.class.isInstance(n)) {
            return (BigDecimal) n;
        } else if (Double.class.isInstance(n)) {
            return BigDecimal.valueOf((Double) n);
        } else {
            return BigDecimal.valueOf((Long) n);
        }
    }

}