All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hu.icellmobilsoft.coffee.module.ruleng.evaluator.AbstractEvaluator Maven / Gradle / Ivy

There is a newer version: 2.9.0
Show newest version
/*-
 * #%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 Annotation cdiSelectLiteral() {
     *     return new RuleQualifier.Literal();
     * }
     * 
* * @return {@code Annotation} */ protected abstract Annotation cdiSelectLiteral(); /** * Extended Rule type, {@link TypeLiteral}. 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy