
nz.co.senanque.rules.OperationsImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of madura-rules Show documentation
Show all versions of madura-rules Show documentation
This is a plugin to Madura Objects. It provides a rules/constraint engine to assist with validation,
deriving new values from user inputs (eg total of invoices entered on this customer) an manipulating metadata
(eg because the amount is above X we make some field readonly). Note that the Java that is using the
monitored objects is quite unaware of the rules layer implemented here. That means you can change rules
without having to go back to your Java code, and it also means you don't have to wonder if everything
implemented the same rules. Anything using that Java object has the rules (unless you turn them all off).
/*******************************************************************************
* 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 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 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 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 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 list)
{
if (list == null)
{
return Boolean.TRUE;
}
int size = list.size();
int index = 0;
for (ProxyField proxyField: list)
{
for (int i=index+1;i list,final List 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);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy