
nz.co.senanque.rules.RuleSessionImpl 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.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import nz.co.senanque.rules.annotations.InternalFunction;
import nz.co.senanque.validationengine.ConvertUtils;
import nz.co.senanque.validationengine.ObjectMetadata;
import nz.co.senanque.validationengine.ProxyField;
import nz.co.senanque.validationengine.ProxyObject;
import nz.co.senanque.validationengine.ValidationException;
import nz.co.senanque.validationengine.ValidationObject;
import nz.co.senanque.validationengine.ValidationSession;
import nz.co.senanque.validationengine.choicelists.ChoiceBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.MessageSourceAccessor;
/**
*
*
* A session is the link between a Package (containing rules) and a DOM (containing data)
* The public interface to this class is the main interface to the engine.
* @author Roger Parkinson
* @version $Revision: 1.12 $
*
*/
public final class RuleSessionImpl implements RuleSession, Serializable
{
private static final long serialVersionUID = -1L;
private final transient static Logger s_log = LoggerFactory.getLogger(RuleSessionImpl.class);
private final RulesPlugin m_plugin;
private ValidationSession m_session;
private final Indenter m_indenter = new Indenter();
private final Set m_resettingRules = new HashSet();
private final Set m_firedRules = new HashSet();
private final Map m_boundObjects = new IdentityHashMap();
private final Set m_unbinding = new TreeSet<>();
private final Map m_ruleProxyFields = new HashMap();
private final Set m_agenda = new HashSet();
private final Set m_reviewList = new HashSet();
private Set m_assignedFields = new HashSet();
private Set m_unknownFields = new HashSet();
private Map m_ruleContextsMap = new HashMap();
private Set m_readOnlyFields = new HashSet();
private Set m_activateFields = new HashSet();
private Set m_requiredFields = new HashSet();
private Set m_excludes = new HashSet();
private final transient MessageSourceAccessor m_messageSourceAccessor;
private Set m_evaluating = new HashSet();
private boolean m_open=true;
protected RuleSessionImpl(final RulesPlugin plugin, final ValidationSession session)
{
m_plugin = plugin;
m_session = session;
m_messageSourceAccessor = new MessageSourceAccessor(m_session.getValidationEngine().getMessageSource());
}
public RuleProxyField getRuleProxyField(final ProxyField proxyField)
{
RuleProxyField ruleProxyField = m_ruleProxyFields.get(proxyField);
if (ruleProxyField == null)
{
ruleProxyField = new RuleProxyField(proxyField,m_indenter,this);
m_ruleProxyFields.put(proxyField,ruleProxyField);
}
return ruleProxyField;
}
protected RuleContext getRuleContext(final Rule rule, final ValidationObject validationObject, final ValidationObject ownerObject) throws FailsToMatchException
{
ValidationObject o = validationObject;
ClassReference cr = this.m_plugin.getClassReferenceMap().get(rule.getClassName());
Class> ruleScope = cr.getClazz();
Class> validationClass = validationObject.getClass();
if (!ruleScope.isAssignableFrom(validationClass))
{
if (ownerObject == null)
{
throw new FailsToMatchException("Fatal internal error. "+o.getClass().getSimpleName()+" fails to match "+rule.getClassName());
}
o = ownerObject;
if (!ruleScope.isAssignableFrom(ownerObject.getClass()))
{
throw new FailsToMatchException("Fatal internal error. "+o.getClass().getSimpleName()+" fails to match "+rule.getClassName());
}
}
final String key = RuleContext.getKey(rule, o);
RuleContext ret = m_ruleContextsMap.get(key);
if (ret == null)
{
ret = new RuleContext(rule,this,m_indenter,o);
m_ruleContextsMap.put(key,ret);
}
return ret;
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getOperations()
*/
public Operations getOperations()
{
return m_plugin.getOperations();
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getMetadata(nz.co.senanque.validationengine.ValidationObject)
*/
public ObjectMetadata getMetadata(ValidationObject object)
{
return m_session.getMetadata(object);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getSession()
*/
public ValidationSession getSession()
{
return m_session;
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#setValue(nz.co.senanque.rules.RuleProxyField, java.lang.Object)
*/
public void setValue(final RuleProxyField proxyField, final Object value)
{
final List newValues = new ArrayList();
newValues.add(new ProposedValue(proxyField,value));
setValues(newValues);
}
protected boolean alreadyFired(final RuleContext ruleContext)
{
if (m_firedRules.contains(ruleContext))
{
return true;
}
m_firedRules.add(ruleContext);
return false;
}
protected void forwardChain()
{
s_log.debug("{}Forward Chain...",m_indenter);
m_indenter.increment();
final Set rules = new HashSet();
m_firedRules.clear();
while (m_agenda.size() > 0)
{
rules.clear();
for (RuleProxyField proxy: m_agenda)
{
s_log.debug("{}agenda item: {}",m_indenter,proxy.toString());
List ruleContexts = proxy.getInputRules();
rules.addAll(ruleContexts);
}
if (s_log.isDebugEnabled())
{
s_log.debug("{}rules to fire:{}",m_indenter,rules.size());
m_indenter.increment();
for (RuleContext rule: rules)
{
s_log.debug("{}{}",m_indenter,rule);
}
m_indenter.decrement();
}
clearAgenda();
for (RuleContext ruleContext: rules)
{
ruleContext.fire();
}
}
m_indenter.decrement();
s_log.debug("{}Completed Forward Chain",m_indenter);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#clearDerived()
*/
public List clearDerived()
{
List ret = new ArrayList();
List proxyObjects = m_session.getProxyObjects();
for (ProxyObject proxyObject: proxyObjects)
{
for (Map.Entry entry: proxyObject.getFieldMap().entrySet())
{
ProxyField proxyField = entry.getValue();
if (proxyField.isDerived())
{
RuleProxyField ruleProxyField = m_ruleProxyFields.get(proxyField);
ret.add(ruleProxyField);
ruleProxyField.reset();
}
}
}
return ret;
}
protected void addToAgenda(RuleProxyField ruleProxyField)
{
if (m_agenda.contains(ruleProxyField))
{
return;
}
s_log.debug("{}adding to agenda {}",m_indenter,ruleProxyField);
m_agenda.add(ruleProxyField);
}
protected void clearAgenda()
{
s_log.debug("{}clearing agenda",m_indenter);
m_agenda.clear();
}
/**
* Method alreadyResettingRule.
* Sometimes a rule attempts to reset twice and gets into a loop
* This checks for that situation. Rules only need to be reset once.
* @param rc
* @return boolean
*/
protected boolean alreadyResettingRule(final RuleContext rc)
{
if (m_resettingRules.contains(rc))
{
return true;
}
m_resettingRules.add(rc);
return false;
}
public boolean alreadyEvaluating(RuleProxyField ruleProxyField) {
if (m_evaluating.contains(ruleProxyField))
{
return true;
}
m_evaluating.add(ruleProxyField);
return false;
}
public void clearEvaluating()
{
m_evaluating.clear();
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#setValues(java.util.List)
*/
public void setValues(List values)
throws InferenceException
{
m_resettingRules.clear();
m_assignedFields.clear();
m_readOnlyFields.clear();
m_activateFields.clear();
m_requiredFields.clear();
m_excludes.clear();
@SuppressWarnings("unused")
int count=0;
m_indenter.clear();
s_log.debug("{}Setting values...",m_indenter);
m_indenter.increment();
for (ProposedValue pv: values)
{
RuleProxyField rpf = null;
count++;
try
{
rpf = pv.getRuleProxyField();
addToAgenda(rpf);
rpf.reset();
rpf.setValue(pv.getValue());
}
catch (InferenceException e)
{
clearAgenda();
throw e;
}
finally
{
removeUnknownField(rpf.getProxyField());
m_resettingRules.clear();
clearReviewList();
}
}
try
{
forwardChain();
}
catch (InferenceException e)
{
s_log.error(e.getMessage(),e);
throw e;
}
catch (ConstraintViolationException e)
{
s_log.error(e.getMessage(),e);
throw e;
}
catch (ValidationException e)
{
s_log.error(e.getMessage(),e);
throw e;
}
finally
{
clearAgenda();
m_resettingRules.clear();
clearReviewList();
}
m_indenter.clear();
// This effectively commits the changes to the exposed data
boolean enabled = m_session.isEnabled();
m_session.setEnabled(false);
for (ProxyField proxyField: m_assignedFields)
{
proxyField.updateValue();
}
for (ProxyField proxyField: m_unknownFields)
{
proxyField.getFieldMetadata().setUnknown(true);
}
m_unknownFields.clear();
for (ProxyField proxyField: m_activateFields)
{
proxyField.setInActive(false);
}
for (ProxyField proxyField: m_readOnlyFields)
{
proxyField.setReadOnly(true);
}
for (ProxyField proxyField: m_requiredFields)
{
proxyField.setRequired(true);
}
for (Exclude exclude: m_excludes)
{
ProxyField proxyField = exclude.getProxyField();
proxyField.exclude(exclude.getKey());
exclude.getRuleContext().addExclude(exclude);
}
m_session.setEnabled(enabled);
s_log.debug("Finished Setting values");
}
/**
* Method addToReviewList.
* @param proxyField
*/
protected void addToReviewList(RuleProxyField proxyField)
{
m_reviewList.add(proxyField);
}
protected void clearReviewList()
{
for (RuleProxyField proxyField: m_reviewList)
{
proxyField.setNeedsReset(false);
}
m_reviewList.clear();
}
/**
* Method killRuleContext.
* @param rc
*/
protected void killRuleContext(final RuleContext rc)
{
m_ruleContextsMap.remove(rc.getKey());
}
/**
* @param proxyField
* @return true if required
*/
public static boolean isRequired(RuleProxyField proxyField)
{
return proxyField.isRequired();
}
protected void log(Object[] messages)
{
s_log.debug("{}{}",m_indenter,messages);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getIndenter()
*/
public Indenter getIndenter()
{
return m_indenter;
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#removeRuleProxyField(nz.co.senanque.validationengine.ProxyField)
*/
public void removeRuleProxyField(ProxyField proxyField)
{
// TODO: if this is a complex object it may have attached fields to remove as well
m_ruleProxyFields.remove(proxyField);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#assign(nz.co.senanque.rules.RuleContext, java.lang.Object, nz.co.senanque.validationengine.ProxyField)
*/
@InternalFunction(operator="=", precedence=1,isAssign=true)
public void assign(RuleContext ruleContext, Object value, RuleProxyField target)
{
s_log.debug("{}assign: {} {}",new Object[]{m_indenter,target,value});
assign(target,value,ruleContext,true);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#assign(nz.co.senanque.rules.RuleContext, java.lang.Object, java.util.List)
*/
public void assign(RuleContext ruleContext, Object value, List list)
{
for (ProxyField proxyField: list)
{
assign(getRuleProxyField(proxyField),value,ruleContext,true);
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#assign(nz.co.senanque.validationengine.ProxyField, java.lang.Object, nz.co.senanque.rules.RuleContext, boolean)
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void assign(RuleProxyField target, Object value, RuleContext ruleContext, boolean dummy)
{
ProxyField target1 = target.getProxyField();
Class> clazz = target1.getPropertyMetadata().getSetMethod().getParameterTypes()[0];
if (value instanceof List>)
{
List sourceList = (List)value;
RuleProxyField rpf = target;
for (ProxyField pf: sourceList)
{
Object listValue = pf.getValue();
if (rpf.isDifferent(listValue))
{
if (isExcluded(target1,String.valueOf(listValue)))
{
String message = m_messageSourceAccessor.getMessage("nz.co.senanque.rules.excluded.value", new Object[]{ listValue, target1.getFieldName()});
throw new InferenceException(message);
}
if (listValue != null && !clazz.isAssignableFrom(listValue.getClass()))
{
listValue = ConvertUtils.convertToComparable((Class)clazz, listValue,m_messageSourceAccessor);
}
addAssignedField(target1);
target.assign(listValue);
addToAgenda(rpf);
}
ruleContext.addAssign(rpf);
}
return;
}
if (value != null && !clazz.isAssignableFrom(value.getClass()))
{
value = ConvertUtils.convertToComparable((Class)clazz, value,m_messageSourceAccessor);
}
RuleProxyField rpf = getRuleProxyField(target1);
if (rpf.isDifferent(value))
{
if (isExcluded(target1,String.valueOf(value)))
{
String message = m_messageSourceAccessor.getMessage("nz.co.senanque.rules.excluded.value", new Object[]{ value, target1.getFieldName()});
throw new InferenceException(message);
}
addAssignedField(target1);
removeUnknownField(target1);
target.assign(value);
addToAgenda(rpf);
}
ruleContext.addAssign(rpf);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#addAssignedField(nz.co.senanque.validationengine.ProxyField)
*/
public void addAssignedField(ProxyField proxyField)
{
m_assignedFields.add(proxyField);
}
public void addUnknownField(ProxyField proxyField)
{
if (!m_unknownFields.contains(proxyField))
{
m_unknownFields.add(proxyField);
}
}
public void removeUnknownField(ProxyField proxyField)
{
m_unknownFields.remove(proxyField);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#bind(nz.co.senanque.validationengine.ValidationObject, nz.co.senanque.validationengine.ProxyField, nz.co.senanque.rules.FieldReference, nz.co.senanque.validationengine.ValidationObject)
*/
public void bind(final ValidationObject validationObject, final ProxyField proxyField, final FieldReference fieldReference, final ValidationObject owner)
{
final RuleProxyField ruleProxyField = getRuleProxyField(proxyField);
for (Rule rule: fieldReference.getListeners())
{
RuleContext ruleContext;
try {
ruleContext = getRuleContext(rule,validationObject,(owner==null)?validationObject:owner);
} catch (FailsToMatchException e) {
continue;
}
ruleProxyField.addInputRule(ruleContext);
}
for (Rule rule: fieldReference.getOutputs())
{
RuleContext ruleContext;
try {
ruleContext = getRuleContext(rule,validationObject,(owner==null)?validationObject:owner);
} catch (FailsToMatchException e) {
continue;
}
ruleProxyField.addOutputRule(ruleContext);
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#bind(nz.co.senanque.validationengine.ValidationObject)
*/
public boolean bind(ValidationObject validationObject)
{
if (m_boundObjects.containsKey(validationObject))
{
return false;
}
m_boundObjects.put(validationObject,validationObject);
return true;
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#bind(nz.co.senanque.validationengine.ValidationObject, nz.co.senanque.validationengine.ProxyField, nz.co.senanque.rules.FieldReference, nz.co.senanque.validationengine.ValidationObject)
*/
public void unbind(final ValidationObject validationObject, final ProxyField proxyField, final FieldReference fieldReference, final ValidationObject owner)
{
final RuleProxyField ruleProxyField = getRuleProxyField(proxyField);
for (Rule rule: fieldReference.getListeners())
{
RuleContext ruleContext;
try {
ruleContext = getRuleContext(rule,validationObject,(owner==null)?validationObject:owner);
} catch (FailsToMatchException e) {
continue;
}
ruleProxyField.removeInputRule(ruleContext);
}
removeRuleProxyField(proxyField);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#bind(nz.co.senanque.validationengine.ValidationObject)
*/
public void unbind(ValidationObject validationObject)
{
Integer id = System.identityHashCode(validationObject);
m_unbinding.add(id);
List proposedValues = new ArrayList();
ProxyObject proxyObject = getSession().getProxyObject(validationObject);
for (ProxyField proxyField: proxyObject.getFieldMap().values())
{
if (!proxyField.isDerived())
{
// Figure out if this property contains a list or a known object type
// we want to ignore those and only reset primitive objects (long, String etc)
Class> clazz = proxyField.getPropertyMetadata().getGetMethod().getReturnType();
if (clazz.isAssignableFrom(List.class))
{
continue;
}
if (getSession().getValidationEngine().getClassMetadata(clazz) != null)
{
continue;
}
RuleProxyField ruleProxyField = getRuleProxyField(proxyField);
if (ruleProxyField.isDifferent(proxyField.getInitialValue()))
{
ProposedValue pv = new ProposedValue(ruleProxyField,proxyField.getInitialValue());
proposedValues.add(pv);
}
}
}
setValues(proposedValues);
m_boundObjects.remove(id);
m_unbinding.remove(id);
List kill = new ArrayList();
for (Map.Entry entry: m_ruleContextsMap.entrySet())
{
if (entry.getValue().getValidationObject() == validationObject)
{
kill.add(entry.getKey());
}
}
for (String key: kill)
{
RuleContext rc = m_ruleContextsMap.remove(key);
rc.reset();
}
}
public boolean isUnbinding(ValidationObject validationObject) {
return (m_unbinding.contains(System.identityHashCode(validationObject)));
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#activate(nz.co.senanque.rules.RuleContext, nz.co.senanque.validationengine.ProxyField)
*/
@InternalFunction(precedence=1,isAssign=true)
public void activate(RuleContext ruleContext,RuleProxyField ruleProxyField)
{
setActivate(ruleProxyField,ruleContext);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#setActivate(nz.co.senanque.validationengine.ProxyField, nz.co.senanque.rules.RuleContext)
*/
public void setActivate(RuleProxyField ruleProxyField,
RuleContext ruleContext)
{
if (ruleProxyField.isInActive()) // only do it if the field changes
{
m_activateFields.add(ruleProxyField.getProxyField());
ruleContext.addActivate(ruleProxyField);
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#readonly(nz.co.senanque.rules.RuleContext, nz.co.senanque.validationengine.ProxyField)
*/
@InternalFunction(precedence=1,isAssign=true)
public void readonly(RuleContext ruleContext,RuleProxyField ruleProxyField)
{
setReadOnly(ruleProxyField,ruleContext);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#setReadOnly(nz.co.senanque.validationengine.ProxyField, nz.co.senanque.rules.RuleContext)
*/
public void setReadOnly(RuleProxyField ruleProxyField,
RuleContext ruleContext)
{
if (!ruleProxyField.isReadOnly()) // only do it if the field changes
{
m_readOnlyFields.add(ruleProxyField.getProxyField());
ruleContext.addReadOnly(ruleProxyField);
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#require(nz.co.senanque.rules.RuleContext, nz.co.senanque.validationengine.ProxyField)
*/
@InternalFunction(precedence=1,isAssign=true)
public void require(RuleContext ruleContext,RuleProxyField ruleProxyField)
{
setRequired(ruleProxyField,ruleContext);
}
@InternalFunction(precedence=1,isAssign=false)
public boolean isNotKnown(RuleProxyField ruleProxyField)
{
return ruleProxyField.getProxyField().isNotKnown();
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#setRequired(nz.co.senanque.validationengine.ProxyField, nz.co.senanque.rules.RuleContext)
*/
public void setRequired(RuleProxyField ruleProxyField,
RuleContext ruleContext)
{
{
if (!ruleProxyField.isRequired()) // only do it if the field changes
{
m_requiredFields.add(ruleProxyField.getProxyField());
ruleContext.addRequired(ruleProxyField);
}
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#exclude(nz.co.senanque.rules.RuleContext, java.lang.String, nz.co.senanque.validationengine.ProxyField)
*/
@InternalFunction(precedence=1,isAssign=true)
public void exclude(RuleContext ruleContext, String key, RuleProxyField proxyField)
{
exclude(proxyField,key,ruleContext);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#exclude(nz.co.senanque.validationengine.ProxyField, java.lang.String, nz.co.senanque.rules.RuleContext)
*/
public void exclude(RuleProxyField ruleProxyField, String key,
RuleContext ruleContext)
{
if (key.equals(ruleProxyField.getValue())) // this does not match when it should
{
String message = m_messageSourceAccessor.getMessage("nz.co.senanque.rules.invalid.exclude",
new Object[]
{ ruleProxyField.getPropertyMetadata().getLabelName(), key });
throw new InferenceException(message);
}
s_log.debug("Excluding {} for {}", key, ruleProxyField.getProxyField().getFieldName());
if (!isExcluded(ruleProxyField.getProxyField(),key)) // only do this if not already excluded
{
Exclude exclude = new Exclude(ruleProxyField.getProxyField(), key,ruleContext);
m_excludes.add(exclude);
s_log.debug("{}excluding: {} {}",new Object[]{m_indenter,ruleProxyField,key});
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#autoAssign(nz.co.senanque.validationengine.ProxyField, nz.co.senanque.rules.RuleContext)
*/
public void autoAssign(ProxyField proxyField, RuleContext ruleContext)
{
// Count the excludes left and if only 1 then assign this value.
// TODO: work out what should happen if a later rule excludes this value
ChoiceBase lastChoice = findLastChoice(proxyField);
if (lastChoice != null)
{
Object value = proxyField.getPropertyMetadata().convertFromString(lastChoice.getKey().toString());
s_log.debug("{}auto-assign: {} {}",new Object[]{m_indenter,proxyField,value});
assign(getRuleProxyField(proxyField),value,ruleContext,true);
}
}
private boolean isExcluded(ProxyField proxyField, String key)
{
if (proxyField.isExcluded(key))
{
return true;
}
for (Exclude exclude: m_excludes)
{
if (exclude.getProxyField().equals(proxyField) && exclude.getKey().equals(key))
{
return true;
}
}
return false;
}
private ChoiceBase findLastChoice(ProxyField proxyField)
{
int count = proxyField.getChoiceList().size();
ChoiceBase ret = null;
for (ChoiceBase choiceBase : proxyField.getChoiceList())
{
if (isExcluded(proxyField, choiceBase.getKey().toString()))
{
count--;
}
else
{
ret = choiceBase;
}
}
if (count == 1)
{
return ret;
}
else
{
return null;
}
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getConstant(java.lang.String)
*/
public String getConstant(String key)
{
return m_plugin.getConstants().get(key);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getMessage(java.lang.String, java.lang.Object[])
*/
public String getMessage(String message, Object[] args)
{
for (int i=0;i)
{
@SuppressWarnings("unchecked")
List list = (List)args[i];
StringBuilder sb = new StringBuilder();
for (ProxyField pf: list)
{
sb.append(String.valueOf(pf.getValue()));
sb.append(",");
}
if (sb.length()>0)
{
args[i] = sb.substring(0, sb.length()-1);
}
else
{
args[i] = "";
}
}
}
return m_messageSourceAccessor.getMessage(message, args);
}
/* (non-Javadoc)
* @see nz.co.senanque.rules.RuleSession#getLastProxyField()
*/
public ProxyField getLastProxyField()
{
if (m_assignedFields.size() == 1)
{
for (ProxyField proxyField: m_assignedFields)
{
return proxyField;
}
}
return null;
}
public String getStats(RuleSession ruleSession) {
return MessageFormat.format("\nRule session has {0} objects bound ruleproxyfields: {1} m_ruleContextsMap: {2}", m_boundObjects.size(), m_ruleProxyFields.size(), m_ruleContextsMap.size());
}
public MessageSourceAccessor getMessageSourceAccessor() {
return m_messageSourceAccessor;
}
public void setOpen(boolean b) {
m_open = b;
}
public boolean isOpen() {
return m_open;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy