/*
* Copyright (c) 2010-2015 Evolveum
*
* 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.evolveum.midpoint.repo.sql.query2.restriction;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.EqualFilter;
import com.evolveum.midpoint.prism.query.GreaterFilter;
import com.evolveum.midpoint.prism.query.LessFilter;
import com.evolveum.midpoint.prism.query.PropertyValueFilter;
import com.evolveum.midpoint.prism.query.SubstringFilter;
import com.evolveum.midpoint.prism.query.ValueFilter;
import com.evolveum.midpoint.repo.sql.query.QueryException;
import com.evolveum.midpoint.repo.sql.query2.resolution.HqlDataInstance;
import com.evolveum.midpoint.repo.sql.query2.InterpretationContext;
import com.evolveum.midpoint.repo.sql.query2.QueryInterpreter2;
import com.evolveum.midpoint.repo.sql.query2.definition.JpaEntityDefinition;
import com.evolveum.midpoint.repo.sql.query2.hqm.RootHibernateQuery;
import com.evolveum.midpoint.repo.sql.query2.hqm.condition.AndCondition;
import com.evolveum.midpoint.repo.sql.query2.hqm.condition.Condition;
import com.evolveum.midpoint.repo.sql.query2.hqm.condition.IsNotNullCondition;
import com.evolveum.midpoint.repo.sql.query2.hqm.condition.IsNullCondition;
import com.evolveum.midpoint.repo.sql.query2.matcher.Matcher;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
/**
* Abstract superclass for all value-related filters. There are two major problems solved:
* 1) mapping from ItemPath to HQL property paths
* 2) adding joined entities to the query, along with necessary conditions
*
* After the necessary entity is available, the fine work (creating one or more conditions
* to execute the filtering) is done by subclasses of this path in the interpretInternal(..) method.
*
* @author lazyman
* @author mederly
*/
public abstract class ItemValueRestriction<T extends ValueFilter> extends ItemRestriction<T> {
private static final Trace LOGGER = TraceManager.getTrace(ItemValueRestriction.class);
public ItemValueRestriction(InterpretationContext context, T filter, JpaEntityDefinition baseEntityDefinition, Restriction parent) {
super(context, filter, filter.getFullPath(), filter.getDefinition(), baseEntityDefinition, parent);
}
@Override
public Condition interpret() throws QueryException {
ItemPath path = getItemPath();
if (ItemPath.isNullOrEmpty(path)) {
throw new QueryException("Null or empty path for ItemValueRestriction in " + filter.debugDump());
}
HqlDataInstance dataInstance = getItemPathResolver().resolveItemPath(path, itemDefinition, getBaseHqlEntity(), false);
setHqlDataInstance(dataInstance);
Condition condition = interpretInternal();
return condition;
}
public abstract Condition interpretInternal() throws QueryException;
protected Condition createPropertyVsConstantCondition(String hqlPropertyPath, Object value, ValueFilter filter) throws QueryException {
ItemRestrictionOperation operation = findOperationForFilter(filter);
InterpretationContext context = getContext();
QueryInterpreter2 interpreter = context.getInterpreter();
Matcher matcher = interpreter.findMatcher(value);
String matchingRule = filter.getMatchingRule() != null ? filter.getMatchingRule().getLocalPart() : null;
// TODO treat null for multivalued properties (at least throw an exception!)
return matcher.match(context.getHibernateQuery(), operation, hqlPropertyPath, value, matchingRule);
}
protected ItemRestrictionOperation findOperationForFilter(ValueFilter filter) throws QueryException {
ItemRestrictionOperation operation;
if (filter instanceof EqualFilter) {
operation = ItemRestrictionOperation.EQ;
} else if (filter instanceof GreaterFilter) {
GreaterFilter gf = (GreaterFilter) filter;
operation = gf.isEquals() ? ItemRestrictionOperation.GE : ItemRestrictionOperation.GT;
} else if (filter instanceof LessFilter) {
LessFilter lf = (LessFilter) filter;
operation = lf.isEquals() ? ItemRestrictionOperation.LE : ItemRestrictionOperation.LT;
} else if (filter instanceof SubstringFilter) {
SubstringFilter substring = (SubstringFilter) filter;
if (substring.isAnchorEnd()) {
operation = ItemRestrictionOperation.ENDS_WITH;
} else if (substring.isAnchorStart()) {
operation = ItemRestrictionOperation.STARTS_WITH;
} else {
operation = ItemRestrictionOperation.SUBSTRING;
}
} else {
throw new QueryException("Can't translate filter '" + filter + "' to operation.");
}
return operation;
}
protected Object getValue(PropertyValueFilter filter) throws QueryException {
PrismValue val = filter.getSingleValue();
if (val == null) {
return null;
} else if (val instanceof PrismPropertyValue) {
PrismPropertyValue propertyValue = (PrismPropertyValue) val;
return propertyValue.getValue();
} else {
throw new QueryException("Non-property value in filter: " + filter + ": " + val.getClass());
}
}
/**
* Filter of type NOT(PROPERTY=VALUE) causes problems when there are entities with PROPERTY set to NULL.
*
* Such a filter has to be treated like
*
* NOT (PROPERTY=VALUE & PROPERTY IS NOT NULL)
*
* TODO implement for restrictions other than PropertyRestriction.
*/
protected Condition addIsNotNullIfNecessary(Condition condition, String propertyPath) {
if (condition instanceof IsNullCondition || condition instanceof IsNotNullCondition) {
return condition;
}
if (!isNegated()) {
return condition;
}
RootHibernateQuery hibernateQuery = getContext().getHibernateQuery();
AndCondition conjunction = hibernateQuery.createAnd();
conjunction.add(condition);
conjunction.add(hibernateQuery.createIsNotNull(propertyPath));
return conjunction;
}
}