/**
*
* Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
*
* 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 com.speedment.runtime.field.internal.predicate;
import com.speedment.runtime.field.predicate.CombinedPredicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static java.util.Objects.requireNonNull;
import java.util.function.Predicate;
import static java.util.stream.Collectors.joining;
import java.util.stream.Stream;
/**
* Immutable aggregation of a number of {@link Predicate Predicates} of the same type
* (e.g. AND or OR) that can be applied in combination.
*
* @param <ENTITY> the entity type
*
* @author Per Minborg
* @author Emil Forslund
* @since 2.2.0
*/
public abstract class AbstractCombinedPredicate<ENTITY> extends AbstractPredicate<ENTITY>
implements CombinedPredicate<ENTITY> {
private final List<Predicate<? super ENTITY>> predicates;
private final Type type;
private AbstractCombinedPredicate(
final Type type,
final List<Predicate<? super ENTITY>> predicates,
final boolean negated
) {
super(negated);
this.type = requireNonNull(type);
this.predicates = new ArrayList<>(requireNonNull(predicates));
}
@Override
public Stream<Predicate<? super ENTITY>> stream() {
return predicates.stream();
}
@Override
public int size() {
return predicates.size();
}
protected List<Predicate<? super ENTITY>> getPredicates() {
return Collections.unmodifiableList(predicates);
}
@Override
public Type getType() {
return type;
}
@Override
public abstract AndCombinedBasePredicate<ENTITY> and(Predicate<? super ENTITY> other);
@Override
public abstract OrCombinedBasePredicate<ENTITY> or(Predicate<? super ENTITY> other);
public static class AndCombinedBasePredicate<ENTITY> extends AbstractCombinedPredicate<ENTITY> {
public AndCombinedBasePredicate(
final List<Predicate<? super ENTITY>> predicates,
final boolean negated
) {
super(Type.AND, requireNonNull(predicates), negated);
}
@Override
protected boolean testWithoutNegation(ENTITY entity) {
requireNonNull(entity);
return stream().allMatch(p -> p.test(entity));
}
@Override
public AndCombinedBasePredicate<ENTITY> and(Predicate<? super ENTITY> other) {
requireNonNull(other);
final List<Predicate<? super ENTITY>> updatedPredicates = new ArrayList<>(getPredicates());
updatedPredicates.add(other);
return new AndCombinedBasePredicate<>(updatedPredicates, isNegated());
}
@Override
public OrCombinedBasePredicate<ENTITY> or(Predicate<? super ENTITY> other) {
requireNonNull(other);
return new OrCombinedBasePredicate<>(Arrays.asList(this, other), false);
}
@Override
public AndCombinedBasePredicate<ENTITY> negate() {
return new AndCombinedBasePredicate<>(getPredicates(), !isNegated());
}
}
public static class OrCombinedBasePredicate<ENTITY> extends AbstractCombinedPredicate<ENTITY> {
public OrCombinedBasePredicate(
final List<Predicate<? super ENTITY>> predicates,
final boolean negated
) {
super(Type.OR, requireNonNull(predicates), negated);
}
@Override
protected boolean testWithoutNegation(ENTITY entity) {
requireNonNull(entity);
return stream().anyMatch(p -> p.test(entity));
}
@Override
public AndCombinedBasePredicate<ENTITY> and(Predicate<? super ENTITY> other) {
requireNonNull(other);
return new AndCombinedBasePredicate<>(Arrays.asList(this, other), false);
}
@Override
public OrCombinedBasePredicate<ENTITY> or(Predicate<? super ENTITY> other) {
requireNonNull(other);
final List<Predicate<? super ENTITY>> updatedPredicates = new ArrayList<>(getPredicates());
updatedPredicates.add(other);
return new OrCombinedBasePredicate<>(updatedPredicates, isNegated());
}
@Override
public OrCombinedBasePredicate<ENTITY> negate() {
return new OrCombinedBasePredicate<>(getPredicates(), !isNegated());
}
}
@Override
public String toString() {
return "CombinedPredicate {type="
+ type.name()
+ ", negated="
+ isNegated()
+ ", predicates="
+ predicates.stream()
.map(Object::toString)
.collect(joining(", "))
+ "}";
}
}