Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*-
* #%L
* Coffee
* %%
* Copyright (C) 2020 i-Cell Mobilsoft Zrt.
* %%
* 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.
* #L%
*/
package hu.icellmobilsoft.coffee.module.ruleng.evaluator;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.PreDestroy;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.CDI;
import javax.enterprise.util.TypeLiteral;
import javax.inject.Inject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import hu.icellmobilsoft.coffee.cdi.annotation.Range;
import hu.icellmobilsoft.coffee.cdi.annotation.Version;
import hu.icellmobilsoft.coffee.cdi.logger.AppLogger;
import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger;
import hu.icellmobilsoft.coffee.dto.exception.BaseException;
import hu.icellmobilsoft.coffee.dto.exception.InvalidParameterException;
import hu.icellmobilsoft.coffee.module.ruleng.rule.IRule;
import hu.icellmobilsoft.coffee.module.ruleng.rule.IRuleSelector;
import hu.icellmobilsoft.coffee.module.ruleng.rule.RuleException;
import hu.icellmobilsoft.coffee.module.ruleng.rule.RuleGroup;
import hu.icellmobilsoft.coffee.module.ruleng.rule.RuleResult;
import hu.icellmobilsoft.coffee.tool.utils.annotation.AnnotationUtil;
import hu.icellmobilsoft.coffee.tool.utils.annotation.RangeUtil;
/**
* Base evaluation logic for a single object type. Eg.:
*
*
* @Model
* public class RuleTypeEvaluatorExampleObjectType extends AbstractEvaluator<ExampleObjectType, CustomRuleResult> {
*
* @Override
* protected Annotation cdiSelectLiteral() {
* return new RuleQualifier.Literal();
* }
*
* @Override
* protected TypeLiteral<IRule<ExampleObjectType, CustomRuleResult>> cdiTypeLiteral() {
* return new TypeLiteral<IRule<ExampleObjectType, CustomRuleResult>>() {
* private static final long serialVersionUID = 1L;
* };
* }
*
* }
*
*
* @author imre.scheffer
* @param
* evaluated object type
* @param
* output type of executed evaluations
* @since 1.0.0
*/
public abstract class AbstractEvaluator implements IEvaluator {
@Inject
@ThisLogger
private AppLogger log;
private Map, List>> groupedRules;
private String currentVersion;
/**
* Qualifier which the Rules are annotated with. Eg.:
*
*
* @Override
* protected TypeLiteral<IRule<ExampleObjectType, CustomRuleResult>> cdiTypeLiteral() {
* return new TypeLiteral<IRule<ExampleObjectType, CustomRuleResult>>() {
* private static final long serialVersionUID = 1L;
* };
* }
*
*
* @return {@code TypeLiteral}
*/
protected abstract TypeLiteral> cdiTypeLiteral();
/**
* Rule comparator by {@link IRuleSelector} and Rule class name
*/
protected Comparator> ruleComparator = new Comparator>() {
@Override
public int compare(IRule o1, IRule o2) {
if (o1 instanceof IRuleSelector && o2 instanceof IRuleSelector) {
int comp = ((IRuleSelector) o1).compareTo((IRuleSelector) o2);
if (comp != 0) {
return comp;
}
}
return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName());
}
};
/**
* Function which groups by {@link IRuleSelector}.
*/
protected Function, Enum>> ruleGroupGetter = new Function, Enum>>() {
@Override
public Enum> apply(IRule r) {
if (r instanceof IRuleSelector) {
return ((IRuleSelector) r).group();
}
return RuleGroup.NONE;
}
};
/**
* Initializes Rule instance from CDI container.
*
* @param type
* TypeLiteral, implementation of Rules
* @param annotation
* Qualifier which the Rules are annotated with
* @return CDI Rule instance
*/
protected Instance> initRuleInstances(TypeLiteral> type, Annotation annotation) {
return CDI.current().select(type, annotation);
}
/**
* Prepares a Rule list by grouping and ordering.
*
* @param instance
* Rule list
* @return prepared Rule list
*/
protected Map, List>> prepareRuleInstances(Instance> instance) {
// csoportositas
Map, List>> groupedRules = instance.stream().collect(Collectors.groupingBy(ruleGroupGetter));
// sorbarendezes
groupedRules.values().forEach(l -> Collections.sort(l, ruleComparator));
return groupedRules;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public List evaluate(INPUT input, Long inputIndex) throws BaseException {
if (input == null) {
throw new InvalidParameterException("input is null");
}
List evalResults = new ArrayList<>();
if (groupedRules == null) {
Instance> instances = initRuleInstances(cdiTypeLiteral(), cdiSelectLiteral());
// előkészítés
groupedRules = prepareRuleInstances(instances);
}
for (Entry, List>> ruleEntry : groupedRules.entrySet()) {
try {
for (IRule rule : ruleEntry.getValue()) {
// feldolgozas (validalas) megszakitas lehetosege az exception dobasaban van
if (StringUtils.isNotBlank(getCurrentVersion())) {
// verzio ellenorzes
Version ruleVersionAnnotation = AnnotationUtil.getAnnotation(rule.getClass(), Version.class);
if (ruleVersionAnnotation != null) {
Range[] ranges = ruleVersionAnnotation.include();
if (!RangeUtil.inRanges(ranges, getCurrentVersion())) {
continue;
}
}
}
List ruleResults = applyRule(rule, input, inputIndex);
evalResults.addAll(ruleResults);
}
} catch (RuleException re) {
log.info("Validation break on [{0}] group with [{1}] message", ruleEntry.getKey(), re.getMessage());
evalResults.add((RULERESULT) re.getRuleResult());
}
}
return evalResults;
}
/**
* Applies rule to given input.
*
* @param rule
* rule to apply
* @param input
* input data to apply the rule on
* @param inputIndex
* index of {@code input}, eg. if it's in a list
* @return result of {@code rule} application (either in successful or exceptional case)
* @throws RuleException
* if rule group ordered execution is interrupted
* @throws BaseException
* if case of an unexpected error
*/
protected List applyRule(IRule rule, INPUT input, Long inputIndex) throws RuleException, BaseException {
// ez eleg sokat kepes logolni
// log.trace("apply rule [{0}] to input [{1}] on inputIndex [{2}]", rule.getClass(), input, inputIndex);
List validationResults = new ArrayList<>();
RULERESULT ruleResult = rule.apply(input);
if (ruleResult != null) {
if (inputIndex != null) {
ruleResult.setIndex(inputIndex);
}
validationResults.add(ruleResult);
}
List ruleResults = rule.applyList(input);
if (CollectionUtils.isNotEmpty(ruleResults)) {
if (inputIndex != null) {
ruleResults.stream().forEach(r -> r.setIndex(inputIndex));
}
validationResults.addAll(ruleResults);
}
return validationResults;
}
/**
* Dispose evaluator
*/
@PreDestroy
public void dispose() {
preDestroy(groupedRules);
}
/**
* Rule disposal method, does nothing by default, child classes can override it if manual rule destroy is necessary (ie.: in case of Dependent
* scoped rule implementations)
*
* @param groupedRules
* the rules to dispose
*/
protected void preDestroy(Map, List>> groupedRules) {
// do nothing by default
}
/**
* Getter for the field {@code currentVersion}. Rules are activated in accordance with the current version.
*
* @return currentVersion
*/
public String getCurrentVersion() {
return currentVersion;
}
/**
* Setter for the field {@code currentVersion}. Rules are activated in accordance with the current version.
*
* @param currentVersion
* currentVersion
*/
public void setCurrentVersion(String currentVersion) {
this.currentVersion = currentVersion;
}
}