org.burningwave.Criteria Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of common Show documentation
Show all versions of common Show documentation
A collection of classes with basic functionality
/*
* This file is part of Burningwave Common.
*
* Author: Roberto Gentili
*
* Hosted at: https://github.com/burningwave/common
*
* --
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Roberto Gentili
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.burningwave;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
@SuppressWarnings("unchecked")
public class Criteria, T extends Criteria.TestContext> {
protected UnaryOperator> logicalOperator;
protected BiPredicate predicate;
public static final , T extends Criteria.TestContext> Criteria of(final BiPredicate predicate) {
return new Criteria().allThoseThatMatch(predicate);
}
public static final , T extends Criteria.TestContext> Criteria of(final Predicate predicate) {
return new Criteria().allThoseThatMatch(predicate);
}
public C allThoseThatMatch(final BiPredicate predicate) {
this.predicate = concat(
this.predicate,
predicate::test
);
return (C)this;
}
public C allThoseThatMatch(final Predicate predicate) {
return allThoseThatMatch((context, entity) -> predicate.test(entity)) ;
}
public C and(){
logicalOperator = (predicate) -> this.predicate.and(predicate);
return (C)this;
}
public C and(C criteria) {
return logicOperation(this.createCopy(), criteria.createCopy(), (predicate) -> predicate::and, newInstance());
}
public C or(){
logicalOperator = (predicate) -> this.predicate.or(predicate);
return (C)this;
}
public C or(C criteria) {
return logicOperation(this.createCopy(), criteria.createCopy(), (predicate) -> predicate::or, newInstance());
}
public C negate() {
predicate = predicate.negate();
return (C)this;
}
public C createCopy() {
C copy = newInstance();
copy.predicate = this.predicate;
copy.logicalOperator = this.logicalOperator;
return copy;
}
public Predicate getPredicateOrFalsePredicateIfPredicateIsNull() {
return getPredicate(createTestContext(), false);
}
public Predicate getPredicateOrTruePredicateIfPredicateIsNull() {
return getPredicate(createTestContext(), true);
}
public boolean hasNoPredicate() {
return this.predicate == null;
}
public T testWithFalseResultForNullEntityOrFalseResultForNullPredicate(E entity) {
T context = createTestContext();
testWithFalseResultForNullEntityOrFalseResultForNullPredicate(context, entity);
return context;
}
public T testWithFalseResultForNullEntityOrTrueResultForNullPredicate(E entity) {
T context = createTestContext();
testWithFalseResultForNullEntityOrTrueResultForNullPredicate(context, entity);
return context;
}
public T testWithTrueResultForNullEntityOrFalseResultForNullPredicate(E entity) {
T context = createTestContext();
testWithTrueResultForNullEntityOrFalseResultForNullPredicate(context, entity);
return context;
}
public T testWithTrueResultForNullEntityOrTrueResultForNullPredicate(E entity) {
T context = createTestContext();
testWithTrueResultForNullEntityOrTrueResultForNullPredicate(context, entity);
return context;
}
protected BiPredicate concat(
BiPredicate mainPredicate,
BiPredicate otherPredicate
) {
BiPredicate predicate = concat(mainPredicate, this.logicalOperator, otherPredicate);
this.logicalOperator = null;
return predicate;
}
@SuppressWarnings("hiding")
protected , T extends Criteria.TestContext> BiPredicate concat(
BiPredicate mainPredicate,
UnaryOperator> logicalOperator,
BiPredicate otherPredicate
) {
return Optional.ofNullable(otherPredicate).map(othPred ->
Optional.ofNullable(mainPredicate).map(mainPred ->
consumeLogicalOperator(othPred, logicalOperator)
).orElse(othPred)
).orElse(mainPredicate);
}
protected T createTestContext() {
return (T)TestContext.create((C)this);
}
protected T getContextWithFalsePredicateForNullPredicate() {
T context = createTestContext();
getPredicate(context, false);
return context;
}
protected T getContextWithTruePredicateForNullPredicate() {
T context = createTestContext();
getPredicate(context, true);
return context;
}
protected BiPredicate getPredicateWrapper(
final BiFunction valueSupplier,
final TriPredicate predicate
) {
return getPredicateWrapper((criteria, entity) -> {
V[] array = valueSupplier.apply(criteria, entity);
boolean result = false;
for (int i = 0; i < array.length; i++) {
if (result = predicate.test(criteria, array, i)) {
break;
}
}
return result;
});
}
protected C logicOperation(C leftCriteria, C rightCriteria,
Function, Function, BiPredicate>> binaryOperator,
C targetCriteria
) {
targetCriteria.predicate =
leftCriteria.predicate != null?
(rightCriteria.predicate != null?
binaryOperator.apply(leftCriteria.predicate).apply(rightCriteria.predicate) :
leftCriteria.predicate):
rightCriteria.predicate;
return targetCriteria;
}
protected C newInstance() {
try {
return (C)this.getClass().getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException exc) {
return Throwables.INSTANCE.throwException(exc);
}
}
@SuppressWarnings("hiding")
, T extends Criteria.TestContext> BiPredicate consumeLogicalOperator(
BiPredicate input,
UnaryOperator> logicalOperator
) {
return Optional.ofNullable(logicalOperator).map(logOp -> {
return logicalOperator.apply(input);
}).orElseGet(() ->
Throwables.INSTANCE.throwException(
"A call to and/or method is necessary before calling {} at {}",
Thread.currentThread().getStackTrace()[10].getMethodName(),
Thread.currentThread().getStackTrace()[11]
)
);
}
BiPredicate getPredicateWrapper(
BiPredicate function
) {
return Optional.ofNullable(function).map(innPredWrap ->
(BiPredicate) (criteria, entity) -> innPredWrap.test(criteria, entity)
).orElse(null);
}
private Predicate getPredicate(T context, boolean defaultResult) {
return context.setPredicate(
this.predicate != null?
(entity) ->
context.setEntity(entity).setResult(this.predicate.test(
context,
entity
)).getResult()
: (entity) ->
context.setEntity(entity).setResult(defaultResult).getResult()
).getPredicate();
}
private boolean testWithFalseResultForNullEntityOrFalseResultForNullPredicate(T context, E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicate(context, false).test(ent)).orElseGet(() ->
context.setEntity(entity).setResult(false).getResult()
);
}
private boolean testWithFalseResultForNullEntityOrTrueResultForNullPredicate(T context, E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicate(context, true).test(ent)).orElseGet(() ->
context.setEntity(entity).setResult(false).getResult()
);
}
private boolean testWithTrueResultForNullEntityOrFalseResultForNullPredicate(T context, E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicate(context, false).test(ent)).orElseGet(() ->
context.setEntity(entity).setResult(true).getResult()
);
}
private boolean testWithTrueResultForNullEntityOrTrueResultForNullPredicate(T context, E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicate(context, true).test(ent)).orElseGet(() ->
context.setEntity(entity).setResult(true).getResult()
);
}
public static class Simple> {
protected UnaryOperator> logicalOperator;
protected Predicate predicate;
public C allThoseThatMatch(final Predicate predicate) {
this.predicate = concat(
this.predicate,
predicate::test
);
return (C)this;
}
public C and(){
logicalOperator = (predicate) -> this.predicate.and(predicate);
return (C)this;
}
public C and(C criteria) {
return logicOperation(this.createCopy(), criteria.createCopy(), (predicate) -> predicate::and, newInstance());
}
public C or(){
logicalOperator = (predicate) -> this.predicate.or(predicate);
return (C)this;
}
public C or(C criteria) {
return logicOperation(this.createCopy(), criteria.createCopy(), (predicate) -> predicate::or, newInstance());
}
public C negate() {
predicate = predicate.negate();
return (C)this;
}
public C createCopy() {
C copy = newInstance();
copy.predicate = this.predicate;
copy.logicalOperator = this.logicalOperator;
return copy;
}
public Predicate getPredicateOrFalsePredicateIfPredicateIsNull() {
return getPredicate(false);
}
public Predicate getPredicateOrTruePredicateIfPredicateIsNull() {
return getPredicate(true);
}
public boolean hasNoPredicate() {
return this.predicate == null;
}
public boolean testWithFalseResultForNullEntityOrFalseResultForNullPredicate(E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicateOrFalsePredicateIfPredicateIsNull().test(ent)).orElseGet(() ->
false
);
}
public boolean testWithFalseResultForNullEntityOrTrueResultForNullPredicate(E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicateOrTruePredicateIfPredicateIsNull().test(ent)).orElseGet(() ->
false
);
}
public boolean testWithFalseResultForNullPredicate(E entity) {
return getPredicateOrFalsePredicateIfPredicateIsNull().test(entity);
}
public boolean testWithTrueResultForNullEntityOrFalseResultForNullPredicate(E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicateOrFalsePredicateIfPredicateIsNull().test(ent)).orElseGet(() ->
true
);
}
public boolean testWithTrueResultForNullEntityOrTrueResultForNullPredicate(E entity) {
return Optional.ofNullable(entity).map(ent -> getPredicateOrTruePredicateIfPredicateIsNull().test(ent)).orElseGet(() ->
true
);
}
public boolean testWithTrueResultForNullPredicate(E entity) {
return getPredicateOrTruePredicateIfPredicateIsNull().test(entity);
}
@SuppressWarnings("hiding")
protected > Predicate concat(
Predicate mainPredicate,
UnaryOperator> logicalOperator,
Predicate otherPredicate
) {
return Optional.ofNullable(otherPredicate).map(othPred ->
Optional.ofNullable(mainPredicate).map(mainPred ->
consumeLogicalOperator(othPred, logicalOperator)
).orElse(othPred)
).orElse(mainPredicate);
}
protected Predicate concat(
Predicate mainPredicate,
Predicate otherPredicate
) {
Predicate predicate = concat(mainPredicate, this.logicalOperator, otherPredicate);
this.logicalOperator = null;
return predicate;
}
protected Predicate getPredicateWrapper(
final Function valueSupplier,
final BiPredicate predicate
) {
return getPredicateWrapper((entity) -> {
V[] array = valueSupplier.apply(entity);
boolean result = false;
for (int i = 0; i < array.length; i++) {
if (result = predicate.test(array, i)) {
break;
}
}
return result;
});
}
protected C logicOperation(C leftCriteria, C rightCriteria,
Function, Function, Predicate>> binaryOperator,
C targetCriteria
) {
targetCriteria.predicate =
leftCriteria.predicate != null?
(rightCriteria.predicate != null?
binaryOperator.apply(leftCriteria.predicate).apply(rightCriteria.predicate) :
leftCriteria.predicate):
rightCriteria.predicate;
return targetCriteria;
}
protected C newInstance() {
try {
return (C)this.getClass().getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException exc) {
return Throwables.INSTANCE.throwException(exc);
}
}
@SuppressWarnings("hiding")
> Predicate consumeLogicalOperator (
Predicate input,
UnaryOperator> logicalOperator
) {
return Optional.ofNullable(logicalOperator).map(logOp -> {
return logicalOperator.apply(input);
}).orElseGet(() ->
Throwables.INSTANCE.throwException(
"A call to and/or method is necessary before calling {} at {}",
Thread.currentThread().getStackTrace()[10].getMethodName(),
Thread.currentThread().getStackTrace()[11]
)
);
}
Predicate getPredicateWrapper(
Predicate function
) {
return Optional.ofNullable(function).map(innPredWrap ->
(Predicate) (entity) -> innPredWrap.test(entity)
).orElse(null);
}
private Predicate getPredicate(boolean defaultResult) {
return this.predicate != null?
(entity) -> {
return this.predicate.test(entity);
} :
(entity) -> {
return defaultResult;
};
}
}
public static class TestContext> extends Context {
private enum Elements {
ENTITY,
PREDICATE,
TEST_RESULT,
THIS_CRITERIA
}
protected TestContext(C criteria) {
super();
put(Elements.THIS_CRITERIA, criteria);
}
public static , T extends Criteria.TestContext> TestContext create(C criteria) {
return new TestContext<>(criteria);
}
public C getCriteria() {
return get(Elements.THIS_CRITERIA);
}
public E getEntity() {
return get(Elements.ENTITY);
}
public Predicate getPredicate() {
return get(Elements.PREDICATE);
}
public Boolean getResult() {
return super.get(Elements.TEST_RESULT);
}
> T setEntity(E entity) {
put(Elements.ENTITY, entity);
return (T) this;
}
> T setPredicate(Predicate predicate) {
put(Elements.PREDICATE, predicate);
return (T)this;
}
> T setResult(Boolean result) {
put(Elements.TEST_RESULT, result);
return (T) this;
}
}
}