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

jodd.inex.InExRules Maven / Gradle / Ivy

There is a newer version: 5.3.0
Show newest version
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package jodd.inex;

import java.util.ArrayList;
import java.util.List;

/**
 * A single-class rule engine for includes/excludes filtering logic. It can be used when
 * set of objects has to filtered using includes and excludes rules.
 * For example, when filtering files by file name etc.
 * 

* Rule engine works in one of two modes: *

    *
  • blacklist - when any input is allowed by default and when you specify * explicit excludes. *
  • *
  • whitelist - when any input is disabled by default and when you specify * explicit includes. *
  • *
*

* The logic of this rule engine depends on the current mode. In both cases, * always the inverse rules are considered first. For example, for blacklist * mode, engine first examine excludes, and then includes. This way you can * set any filter combination. *

* All Jodd classes that filters something uses this class to unify the * behavior across the Jodd library. *

* About generics: rule engine examine Values (V). Rules are defined as Definitions (D). * They are stored internally as R, that is used with Values. */ public class InExRules implements InExRuleMatcher { public InExRules create() { return new InExRules<>(); } protected List> rules; protected final InExRuleMatcher inExRuleMatcher; protected int includesCount; protected int excludesCount; protected boolean blacklist = true; /** * Creates default instance. */ public InExRules() { this.inExRuleMatcher = this; } /** * Creates instance that uses provided matcher. */ public InExRules(final InExRuleMatcher inExRuleMatcher) { this.inExRuleMatcher = inExRuleMatcher; } /** * Returns total number of all rules. */ public int totalRules() { if (rules == null) { return 0; } return rules.size(); } /** * Returns total number of include rules. */ public int totalIncludeRules() { return includesCount; } /** * Returns total number of exclude rules. */ public int totalExcludeRules() { return excludesCount; } /** * Returns true if rule engine has at least one rule set. */ public boolean hasRules() { if (rules == null) { return false; } return !rules.isEmpty(); } /** * Rule definition. */ public static class Rule { public final R value; public final boolean include; public Rule(final R value, final boolean include) { this.value = value; this.include = include; } @Override public String toString() { return (include ? "+" : "-") + value.toString(); } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Rule rule = (Rule) o; if (include != rule.include) { return false; } if (!value.equals(rule.value)) { return false; } return true; } @Override public int hashCode() { int result = value.hashCode(); result = 31 * result + (include ? 1 : 0); return result; } } /** * Returns rule's value on given index. */ public R getRule(final int index) { return rules.get(index).value; } /** * Resets all the rules in this rule engine. */ public void reset() { if (rules != null) { rules.clear(); } includesCount = excludesCount = 0; blacklist = true; } /** * Enables blacklist mode - everything is included by default, * and user sets explicit excludes. */ public void blacklist() { blacklist = true; } /** * Returns true if blacklist mode is set. */ public boolean isBlacklist() { return blacklist; } /** * Enables whitelist mode - everything is excluded by default, * and user set explicit includes. */ public void whitelist() { blacklist = false; } /** * Returns true if whitelist mode is set. */ public boolean isWhitelist() { return !blacklist; } /** * Sets blacklist or whitelist mode depending on rules. Smart mode * determines the following: *

    *
  • If there are only include rules, then the {@link #whitelist() whitelist} mode is set.
  • *
  • If there are only excluded rules, then the {@link #blacklist() blacklist} mode is set.
  • *
  • In any other case (both type of rules exist or no rules are set), then mode is not changed.
  • *
* Should be called after all the rules are set, before matching starts. */ public void detectMode() { if (excludesCount == 0 && includesCount > 0) { whitelist(); } else if (excludesCount > 0 && includesCount == 0) { blacklist(); } } /** * Adds include rule. */ public void include(final D rule) { addRule(rule, true); } /** * Adds exclude rule. */ public void exclude(final D rule) { addRule(rule, false); } /** * Adds a rule. Duplicates are not allowed and will be ignored. */ protected void addRule(final D ruleDefinition, final boolean include) { if (rules == null) { rules = new ArrayList<>(); } if (include) { includesCount++; } else { excludesCount++; } Rule newRule = new Rule<>(makeRule(ruleDefinition), include); if (rules.contains(newRule)) { return; } rules.add(newRule); } protected R makeRule(final D rule) { return (R) rule; } /** * Matches value against the set of rules using current white/black list mode. */ public boolean match(final V value) { return match(value, blacklist); } /** * Matches value against the set of rules using provided white/black list mode. */ public boolean match(final V value, final boolean blacklist) { if (rules == null) { return blacklist; } boolean include = blacklist; if (include) { include = processExcludes(value, true); include = processIncludes(value, include); } else { include = processIncludes(value, false); include = processExcludes(value, include); } return include; } /** * Applies rules on given flag using current black/white list mode. * @see #apply(Object, boolean, boolean) */ public boolean apply(final V value, final boolean flag) { return apply(value, blacklist, flag); } /** * Applies rules on given flag. Flag is only changed if at least one rule * matched. Otherwise, the same value is returned. This way you can * chain several rules and have the rule engine change the flag * only when a rule is matched. */ public boolean apply(final V value, final boolean blacklist, boolean flag) { if (rules == null) { return flag; } if (blacklist) { flag = processExcludes(value, flag); flag = processIncludes(value, flag); } else { flag = processIncludes(value, flag); flag = processExcludes(value, flag); } return flag; } /** * Process includes rules. */ protected boolean processIncludes(final V value, boolean include) { if (includesCount > 0) { if (!include) { for (Rule rule : rules) { if (!rule.include) { continue; } if (inExRuleMatcher.accept(value, rule.value, true)) { include = true; break; } } } } return include; } /** * Process excludes rules. */ protected boolean processExcludes(final V value, boolean include) { if (excludesCount > 0) { if (include) { for (Rule rule : rules) { if (rule.include) { continue; } if (inExRuleMatcher.accept(value, rule.value, false)) { include = false; break; } } } } return include; } /** * Matches value against single rule. By default performs equals on value * against the rule. */ @Override public boolean accept(final V value, final R rule, final boolean include) { return value.equals(rule); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy