nz.co.senanque.rules.OperationsImpl.java Source code

Java tutorial

Introduction

Here is the source code for nz.co.senanque.rules.OperationsImpl.java

Source

/*******************************************************************************
 * Copyright (c)2014 Prometheus Consulting
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package nz.co.senanque.rules;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import nz.co.senanque.rules.annotations.InternalFunction;
import nz.co.senanque.validationengine.ListeningArray;
import nz.co.senanque.validationengine.ProxyField;

import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;

/**
 * All expression operations are described here.
 * 
 * @author Roger Parkinson
 * @version $Revision: 1.9 $
 */
public class OperationsImpl implements Operations, Serializable {

    private static final long serialVersionUID = 1L;
    private transient final Date m_today;
    private transient final MessageSource m_messageSource;

    protected OperationsImpl(Date today, MessageSource messageSource) {
        m_today = today;
        m_messageSource = messageSource;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.newrules.Operations#eq(java.lang.Object, java.lang.Object)
     */
    @InternalFunction(operator = "==", precedence = 10)
    public Boolean eq(Object value, Object value2) {
        if (value == null && value2 == null) {
            return Boolean.TRUE;
        }
        if (value != null) {
            return new Boolean((value.equals(value2)));
        }
        return Boolean.FALSE;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.newrules.Operations#gt(java.lang.Object, java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @InternalFunction(operator = ">", precedence = 10)
    public Boolean gt(Object value, Object value2) {
        if (value2 != null && value2 instanceof Comparable) {
            @SuppressWarnings("rawtypes")
            final int ret = ((Comparable) value2).compareTo(value);
            return (ret > 0);
        }
        return null;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.newrules.Operations#gt(java.lang.Object, java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @InternalFunction(operator = "<", precedence = 10)
    public Boolean lt(final Object value, final Object value2) {
        if (value != null && value instanceof Comparable) {
            @SuppressWarnings("rawtypes")
            final int ret = ((Comparable) value2).compareTo(value);
            return (ret < 0);
        }
        return null;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.newrules.Operations#gt(java.lang.Object, java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @InternalFunction(operator = ">=", precedence = 10)
    public Boolean ge(final Object value, final Object value2) {
        if (value != null && value instanceof Comparable) {
            @SuppressWarnings("rawtypes")
            final int ret = ((Comparable) value2).compareTo(value);
            return (ret >= 0);
        }
        return null;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.newrules.Operations#gt(java.lang.Object, java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @InternalFunction(operator = "<=", precedence = 10)
    public Boolean le(final Object value, final Object value2) {
        if (value != null && value instanceof Comparable) {
            @SuppressWarnings("rawtypes")
            final int ret = ((Comparable) value2).compareTo(value);
            return (ret <= 0);
        }
        return null;
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.newrules.Operations#checkTrue(java.lang.Object)
     */
    @InternalFunction()
    public void checkTrue(final Boolean value) throws NotTrueException {
        if (value != null && !value) {
            throw new NotTrueException();
        }
    }

    @InternalFunction()
    public void checkFalse(final Boolean value) throws NotFalseException {
        if (value != null && value) {
            throw new NotFalseException();
        }
    }

    @InternalFunction()
    public Number count(final ListeningArray<?> array) {
        if (array == null) {
            return new Long(0L);
        }
        return new Long(array.size());
    }

    @InternalFunction()
    public Number sum(final List<ProxyField> list) {
        if (list == null) {
            return new Long(0L);
        }
        double ret = 0.0;
        for (ProxyField proxyField : list) {
            ret += getNumericValue(proxyField.getValue());
        }
        return new Long((long) ret);
    }

    private double getNumericValue(Object o) {
        double ret = 0.0;
        if (o == null) {
            return ret;
        }
        if (o instanceof Integer) {
            ret = (Integer) o;
            return ret;
        }
        if (o instanceof Long) {
            ret = (Long) o;
            return ret;
        }
        if (o instanceof Float) {
            ret = (Float) o;
            return ret;
        }
        if (o instanceof Double) {
            ret = (Double) o;
            return ret;
        }
        return ret;
    }

    private boolean getBooleanValue(Object o) {
        boolean ret = false;
        if (o == null) {
            return ret;
        }
        if (o instanceof Boolean) {
            ret = ((Boolean) o).booleanValue();
            return ret;
        }
        return ret;
    }

    @InternalFunction()
    public Boolean anyTrue(final List<ProxyField> list) {
        if (list == null) {
            return Boolean.FALSE;
        }
        for (ProxyField proxyField : list) {
            if (getBooleanValue(proxyField.getValue())) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

    @InternalFunction()
    public Number countTrue(final List<ProxyField> list) {
        if (list == null) {
            return new Long(0L);
        }
        long ret = 0;
        for (ProxyField proxyField : list) {
            if (getBooleanValue(proxyField.getValue())) {
                ret++;
            }
        }
        return ret;
    }

    @InternalFunction()
    public Boolean allTrue(final List<ProxyField> list) {
        if (list == null) {
            return Boolean.FALSE;
        }
        for (ProxyField proxyField : list) {
            if (!getBooleanValue(proxyField.getValue())) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }

    /**
     * Every item in the list must be unique
     * @param list
     * @return true if all unique
     */
    @InternalFunction()
    public Boolean unique(final List<ProxyField> list) {
        if (list == null) {
            return Boolean.TRUE;
        }
        int size = list.size();
        int index = 0;
        for (ProxyField proxyField : list) {
            for (int i = index + 1; i < size; i++) {
                if (list.get(i).getValue().equals(proxyField.getValue())) {
                    return Boolean.FALSE;
                }
            }
        }
        return Boolean.TRUE;
    }

    /**
     * Everything in the first list must be in the second list too
     * But not necessarily the reverse.
     * @param list
     * @param list2
     * @return true if first list is in the second
     */
    @InternalFunction()
    public Boolean match(final List<ProxyField> list, final List<ProxyField> list2) {
        if (list == null) {
            return Boolean.TRUE;
        }
        for (ProxyField proxyField : list) {
            boolean found = false;
            for (ProxyField proxyField2 : list2) {
                if (proxyField.getValue().equals(proxyField2.getValue())) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }

    @InternalFunction(operator = "&&", precedence = 21)
    public Boolean logicalAnd(Boolean value, Boolean value2) {
        if (value == null) {
            return Boolean.FALSE;
        }
        return value && value2;
    }

    @InternalFunction(operator = "!", precedence = 22)
    public Boolean logicalNot(Boolean value) {
        if (value == null) {
            return Boolean.TRUE;
        }
        return !value;
    }

    @InternalFunction(operator = "||", precedence = 5)
    public Boolean logicalOr(Boolean value, Boolean value2) {
        if (value == null || value2 == null) {
            return Boolean.FALSE;
        }
        return value || value2;
    }

    @InternalFunction(operator = "/", precedence = 21)
    public Number div(Number value, Number value2) {
        Number ret = null;
        if (value == null || value2 == null) {
            return new Long(0L);
        }
        if (value.doubleValue() == 0.0) {
            String message = new MessageSourceAccessor(m_messageSource)
                    .getMessage("nz.co.senanque.rules.divide.by.zero");
            throw new InferenceException(message);
        }
        ret = value2.doubleValue() / value.doubleValue();
        return ret;
    }

    @InternalFunction(operator = "%", precedence = 21)
    public Number mod(Number value, Number value2) {
        if (value == null || value2 == null) {
            return new Long(0L);
        }
        return value2.doubleValue() % value.doubleValue();
    }

    @InternalFunction(operator = "*", precedence = 21)
    public Number mul(Number value, Number value2) {
        return value.doubleValue() * value2.doubleValue();
    }

    @InternalFunction(operator = "^", precedence = 22)
    public Number pow(Number value, Number value2) {
        if (value == null || value2 == null) {
            return new Long(0L);
        }
        return Math.pow(value2.doubleValue(), value.doubleValue());
    }

    @InternalFunction(operator = "-", precedence = 20)
    public Number sub(Number value, Number value2) {
        if (value == null || value2 == null) {
            return new Long(0L);
        }
        return value2.doubleValue() - value.doubleValue();
    }

    @InternalFunction(precedence = 20, isHidden = true)
    public String concat(String value, String value2) {
        return value2 + value;
    }

    @InternalFunction(operator = "+", precedence = 20)
    public Number add(Number value, Number value2) {
        if (value == null || value2 == null) {
            return new Long(0L);
        }
        return value2.doubleValue() + value.doubleValue();
    }

    @InternalFunction()
    public Number yearsSince(Date value) {
        if (value == null) {
            return 0.0;
        }
        Calendar today = getToday();
        Calendar c = getCalendar(value);
        int thisYear = today.get(Calendar.YEAR);
        int ret = thisYear - c.get(Calendar.YEAR);
        return new Double(ret);
    }

    @InternalFunction()
    public Number monthsSince(Date value) {
        if (value == null) {
            return 0.0;
        }
        Calendar today = getToday();
        Calendar c = getCalendar(value);
        int thisYear = today.get(Calendar.YEAR);
        int thisMonth = today.get(Calendar.MONTH);
        int ret = ((thisYear - c.get(Calendar.YEAR)) * 12) + (thisMonth - c.get(Calendar.MONTH));
        return new Double(ret);
    }

    @InternalFunction()
    public String format(Object value, String code) {
        if (code == null) {
            return "";
        }
        return new MessageSourceAccessor(m_messageSource).getMessage(code, new Object[] { value });
    }

    private Calendar getCalendar(Date date) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        return calendar;
    }

    @InternalFunction()
    public Date addDays(Date date, Number days) {
        if (date == null || days == null) {
            return null;
        }
        Calendar calendar = getCalendar(date);
        calendar.add(Calendar.DAY_OF_YEAR, days.intValue());
        Date ret = calendar.getTime();
        return ret;
    }

    @InternalFunction()
    public Date subtractDays(Date date, Number days) {
        if (date == null || days == null) {
            return null;
        }
        Calendar calendar = getCalendar(date);
        calendar.add(Calendar.DAY_OF_YEAR, days.intValue() * -1);
        Date ret = calendar.getTime();
        return ret;
    }

    @InternalFunction()
    public Number daysSince(Date value) {
        if (value == null) {
            return 0.0;
        }
        Calendar today = getToday();
        Calendar c = getCalendar(value);
        int thisYear = today.get(Calendar.YEAR);
        int thisDayOfYear = today.get(Calendar.DAY_OF_YEAR);
        int ret = ((thisYear - c.get(Calendar.YEAR)) * 365) + (thisDayOfYear - c.get(Calendar.DAY_OF_YEAR));
        return new Double(ret);
    }

    private Calendar getToday() {
        Calendar today = Calendar.getInstance();
        if (m_today != null) {
            today.setTime(m_today);
        }
        return today;
    }

    //    @InternalFunction()
    //    public Double daysSince(java.util.Date value)
    //    {
    //        Calendar c = Calendar.getInstance();
    //        c.setTime(value);
    //        int thisYear = c.get(Calendar.YEAR);
    //        int thisMonth = c.get(Calendar.DAY_OF_YEAR);
    //        int ret = (thisYear - c.get(Calendar.YEAR))+(thisMonth - c.get(Calendar.DAY_OF_YEAR));
    //        return new Double(ret);
    //    }
    @InternalFunction()
    public Number toNumber(String value) {
        return Double.valueOf(value);
    }

    @InternalFunction()
    public Long toLong(Number value) {
        if (value == null) {
            return new Long(0L);
        }
        return value.longValue();
    }

    @InternalFunction()
    public Date toDate(String value) {
        try {
            Date ret = java.sql.Date.valueOf(value);
            return ret;
        } catch (IllegalArgumentException e) {
            String message = new MessageSourceAccessor(m_messageSource)
                    .getMessage("nz.co.senanque.rules.illegal.date.format", new Object[] { value });
            throw new InferenceException(message);
        }
    }

    @InternalFunction()
    public String toString(Number value) {
        return String.valueOf(value);
    }

    @InternalFunction(isHidden = true)
    public String toStringD(Date value) {
        return String.valueOf(value);
    }

}