blob: ea79d7503069b8bf59cc0a27fbe8acedce2ab2ea [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.openjpa.persistence.criteria;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import org.apache.openjpa.kernel.exps.ExpressionFactory;
import org.apache.openjpa.kernel.exps.Literal;
/**
* Predicate is a expression that evaluates to true or false.
* All boolean expressions are implemented as Predicate.
* A predicate can have zero or more predicate arguments.
* Default predicate operator is AND (conjunction).
* Two constant predicates are Predicate.TRUE and Predicate.FALSE.
* AND predicate with no argument evaluates to TRUE.
* OR predicate with no argument evaluates to FALSE.
* Negation of a Predicate creates a new Predicate.
*
* @author Pinaki Poddar
* @author Fay Wang
*
* @since 2.0.0
*/
abstract class PredicateImpl extends ExpressionImpl<Boolean> implements Predicate {
static final Expression<?> TRUE_CONSTANT = new Expressions.Constant<>(true);
static final Expression<?> FALSE_CONSTANT = new Expressions.Constant<>(false);
private static Predicate TRUE;
private static Predicate FALSE;
protected final List<Predicate> _exps = Collections.synchronizedList(new ArrayList<Predicate>());
private final BooleanOperator _op;
private boolean _negated = false;
/**
* An AND predicate with no arguments.
*/
protected PredicateImpl() {
this(BooleanOperator.AND);
}
/**
* A predicate with the given operator.
*/
protected PredicateImpl(BooleanOperator op) {
super(Boolean.class);
_op = op;
}
/**
* A predicate of given operator with given arguments.
*/
protected PredicateImpl(BooleanOperator op, Predicate...restrictions) {
this(op);
if (restrictions == null || restrictions.length == 0) return;
for (Predicate p : restrictions) {
add(p);
}
}
/**
* Adds the given predicate expression.
*/
public PredicateImpl add(Expression<Boolean> s) {
synchronized (_exps) {
_exps.add((Predicate)s); // all boolean expressions are Predicate
}
return this;
}
@Override
public List<Expression<Boolean>> getExpressions() {
List<Expression<Boolean>> result = new CopyOnWriteArrayList<>();
if (_exps.isEmpty())
return result;
result.addAll(_exps);
return result;
}
@Override
public final BooleanOperator getOperator() {
return _op;
}
public final boolean isEmpty() {
return _exps.isEmpty();
}
/**
* Is this predicate created by negating another predicate?
*/
@Override
public final boolean isNegated() {
return _negated;
}
/**
* Returns a new predicate as the negation of this predicate.
* <br>
* Note:
* Default negation creates a Not expression with this receiver as delegate.
* Derived predicates can return the inverse expression, if exists.
* For example, NotEqual for Equal or LessThan for GreaterThanEqual etc.
*/
@Override
public PredicateImpl not() {
return new Expressions.Not(this).markNegated();
}
protected PredicateImpl markNegated() {
_negated = true;
return this;
}
public static Predicate TRUE() {
if (TRUE == null) {
ExpressionImpl<Integer> ONE = new Expressions.Constant<>(1);
TRUE = new Expressions.Equal(ONE, ONE);
}
return TRUE;
}
public static Predicate FALSE() {
if (FALSE == null) {
ExpressionImpl<Integer> ONE = new Expressions.Constant<>(1);
FALSE = new Expressions.NotEqual(ONE, ONE);
}
return FALSE;
}
@Override
org.apache.openjpa.kernel.exps.Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> q) {
if (_exps.isEmpty()) {
return factory.newLiteral(_op == BooleanOperator.AND, Literal.TYPE_BOOLEAN);
}
throw new AbstractMethodError(this.getClass().getName());
}
@Override
org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, CriteriaQueryImpl<?> q) {
if (_exps.isEmpty()) {
Predicate nil = _op == BooleanOperator.AND ? TRUE() : FALSE();
return ((PredicateImpl)nil).toKernelExpression(factory, q);
}
if (_exps.size() == 1) {
Predicate e0 = _exps.get(0);
if (isNegated())
e0 = e0.not();
return ((PredicateImpl)e0).toKernelExpression(factory, q);
}
ExpressionImpl<?> e1 = (ExpressionImpl<?>)_exps.get(0);
ExpressionImpl<?> e2 = (ExpressionImpl<?>)_exps.get(1);
org.apache.openjpa.kernel.exps.Expression ke1 = e1.toKernelExpression(factory, q);
org.apache.openjpa.kernel.exps.Expression ke2 = e2.toKernelExpression(factory, q);
org.apache.openjpa.kernel.exps.Expression result = _op == BooleanOperator.AND
? factory.and(ke1,ke2) : factory.or(ke1, ke2);
for (int i = 2; i < _exps.size(); i++) {
PredicateImpl p = (PredicateImpl)_exps.get(i);
result = _op == BooleanOperator.AND
? factory.and(result, p.toKernelExpression(factory, q))
: factory.or(result, p.toKernelExpression(factory,q));
}
return _negated ? factory.not(result) : result;
}
@Override
public void acceptVisit(CriteriaExpressionVisitor visitor) {
Expressions.acceptVisit(visitor, this, _exps.toArray(new Expression<?>[_exps.size()]));
}
@Override
public StringBuilder asValue(AliasContext q) {
boolean braces = _exps.size() > 1;
StringBuilder buffer = Expressions.asValue(q, _exps.toArray(new Expression<?>[_exps.size()]), " " +_op + " ");
if (braces) buffer.insert(0, "(").append(")");
if (isNegated()) buffer.insert(0, "NOT ");
return buffer;
}
/**
* Concrete AND predicate.
*
*/
static class And extends PredicateImpl {
public And(Expression<Boolean> x, Expression<Boolean> y) {
super(BooleanOperator.AND);
add(x).add(y);
}
public And(Predicate...restrictions) {
super(BooleanOperator.AND, restrictions);
}
}
/**
* Concrete OR predicate.
*
*/
static class Or extends PredicateImpl {
public Or(Expression<Boolean> x, Expression<Boolean> y) {
super(BooleanOperator.OR);
add(x).add(y);
}
public Or(Predicate...restrictions) {
super(BooleanOperator.OR, restrictions);
}
}
}