com.day.cq.search.eval.RangePropertyPredicateEvaluator Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.search.eval;
import java.math.BigDecimal;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.query.Row;
import org.apache.felix.scr.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.search.Predicate;
/**
* Matches a JCR property against an interval. This applies to properties with
* linear types such as LONG, DOUBLE and DECIMAL. For DATE please see the
* {@link DateRangePredicateEvaluator} that has optimized date format input.
*
*
* You can define a lower bound and an upper bound or only one of them. The
* operation (eg. "lesser than" or "lesser or equals") can also be specified for
* lower and upper bound individually.
*
*
* Does not support facet extraction.
*
*
Name:
* rangeproperty
*
* Properties:
*
* - property
- relative path to property
* - lowerBound
- lower bound to check property for
* - lowerOperation
- ">" (default) or ">=", applies to the lowerValue
* - upperBound
- upper bound to check property for
* - upperOperation
- "<" (default) or "<=", applies to the lowerValue
* - decimal
- "true" if the checked property is of type Decimal
*
*
* @since 5.2
*/
@Component(metatype = false, factory = "com.day.cq.search.eval.PredicateEvaluator/rangeproperty")
public class RangePropertyPredicateEvaluator extends AbstractPredicateEvaluator {
private static final Logger log = LoggerFactory.getLogger(RangePropertyPredicateEvaluator.class);
public static final String PROPERTY = "property";
public static final String LOWER_BOUND = "lowerBound";
public static final String LOWER_OPERATION = "lowerOperation";
public static final String UPPER_BOUND = "upperBound";
public static final String UPPER_OPERATION = "upperOperation";
public static final String PROPERTY_DECIMAL = "decimal";
@Override
public String getXPathExpression(Predicate p, EvaluationContext context) {
if (p.getBool(PROPERTY_DECIMAL)) return null;
return getXPathExpression(p.get(PROPERTY), p.get(LOWER_BOUND), p.get(LOWER_OPERATION), p.get(UPPER_BOUND),
p.get(UPPER_OPERATION));
}
protected String getXPathExpression(String property, String lowerValue, String lowerOperation, String upperValue,
String upperOperation) {
StringBuffer buffer = new StringBuffer();
if (lowerValue != null) {
String op = lowerOperation;
if (!">".equals(op) && !">=".equals(op)) {
op = ">"; // default
}
buffer.append(XPath.getPropertyPath(property)).append(" ").append(op).append(" ").append(lowerValue);
}
if (upperValue != null) {
if (buffer.length() > 1) {
buffer.append(" and ");
}
String op = upperOperation;
if (!"<".equals(op) && !"<=".equals(op)) {
op = "<"; // default
}
buffer.append(XPath.getPropertyPath(property)).append(" ").append(op).append(" ").append(upperValue);
}
if (buffer.length() > 0) {
return "(" + buffer.toString() + ")";
}
else {
return null;
}
}
@Override
public String[] getOrderByProperties(Predicate p, EvaluationContext context) {
return new String[] { p.get(PROPERTY) };
}
@Override
public boolean canXpath(Predicate p, EvaluationContext context) {
return !p.getBool(PROPERTY_DECIMAL);
}
@Override
public boolean canFilter(Predicate p, EvaluationContext context) {
return true;
}
@Override
public boolean includes(final Predicate p, final Row row, final EvaluationContext context) {
return includes(context.getNode(row), p.get(PROPERTY), p.get(LOWER_BOUND), p.get(LOWER_OPERATION),
p.get(UPPER_BOUND), p.get(UPPER_OPERATION), p.getBool(PROPERTY_DECIMAL));
}
protected boolean includes(final Node node, final String property, final String lowerValue,
final String lowerOperation, final String upperValue, final String upperOperation, final boolean decimal) {
if (property == null || property.length() == 0 ||
((lowerValue == null || lowerValue.length() == 0) && (upperValue == null || upperValue.length() == 0))) {
return true;
}
String path = null;
try {
path = node.getPath();
if (!node.hasProperty(property)) {
return false;
}
final Property nodeProperty = node.getProperty(property);
if (decimal) {
if (nodeProperty.getType() != PropertyType.DECIMAL) return false;
if (lowerValue != null) {
final BigDecimal bdLowerValue = new BigDecimal(lowerValue);
if (nodeProperty.isMultiple()) {
boolean match = false;
for (Value value: nodeProperty.getValues()) {
if ((">=".equals(lowerOperation) && value.getDecimal().compareTo(bdLowerValue) >= 0) ||
(!">=".equals(lowerOperation) && value.getDecimal().compareTo(bdLowerValue) > 0)) {
match = true;
break;
}
}
if (!match) return false;
} else if ((">=".equals(lowerOperation) && nodeProperty.getDecimal().compareTo(bdLowerValue) < 0) ||
(!">=".equals(lowerOperation) && nodeProperty.getDecimal().compareTo(bdLowerValue) <= 0)) {
return false;
}
}
if (upperValue != null) {
final BigDecimal bdUpperValue = new BigDecimal(upperValue);
if (nodeProperty.isMultiple()) {
boolean match = false;
for (Value value: nodeProperty.getValues()) {
if (("<=".equals(upperOperation) && value.getDecimal().compareTo(bdUpperValue) <= 0) ||
(!"<=".equals(upperOperation) && value.getDecimal().compareTo(bdUpperValue) < 0)) {
match = true;
break;
}
}
if (!match) return false;
} else if (("<=".equals(upperOperation) && nodeProperty.getDecimal().compareTo(bdUpperValue) > 0) ||
(!"<=".equals(upperOperation) && nodeProperty.getDecimal().compareTo(bdUpperValue) >= 0)) {
return false;
}
}
} else {
boolean longValue = false;
boolean doubleValue = false;
long lLowerValue = 0;
long lUpperValue = 0;
double dLowerValue = 0;
double dUpperValue = 0;
try {
if (lowerValue != null) lLowerValue = Long.parseLong(lowerValue);
if (upperValue != null) lUpperValue = Long.parseLong(upperValue);
longValue = true;
} catch (NumberFormatException e) {
try {
if (lowerValue != null) dLowerValue = Double.parseDouble(lowerValue);
if (upperValue != null) dUpperValue = Double.parseDouble(upperValue);
doubleValue = true;
} catch (NumberFormatException e2) {
log.warn("invalid values for rangeproperty includes <{},{}>", lowerValue, upperValue);
return true;
}
}
if (longValue) {
if (nodeProperty.getType() != PropertyType.LONG) return false;
if (lowerValue != null) {
if (nodeProperty.isMultiple()) {
boolean match = false;
for (Value value: nodeProperty.getValues()) {
if ((">=".equals(lowerOperation) && value.getLong() >= lLowerValue) ||
(!">=".equals(lowerOperation) && value.getLong() > lLowerValue)) {
match = true;
break;
}
}
if (!match) return false;
} else if ((">=".equals(upperOperation) && nodeProperty.getLong() < lUpperValue) ||
(!">".equals(upperOperation) && nodeProperty.getLong() <= lUpperValue)) {
return false;
}
}
if (upperValue != null) {
if (nodeProperty.isMultiple()) {
boolean match = false;
for (Value value: nodeProperty.getValues()) {
if (("<=".equals(upperOperation) && value.getLong() <= lUpperValue) ||
(!"<=".equals(upperOperation) && value.getLong() < lUpperValue)) {
match = true;
break;
}
}
if (!match) return false;
} else if (("<=".equals(upperOperation) && nodeProperty.getLong() > lUpperValue) ||
(!"<=".equals(upperOperation) && nodeProperty.getLong() >= lUpperValue)) {
return false;
}
}
} else if (doubleValue) {
if (nodeProperty.getType() != PropertyType.DOUBLE) return false;
if (lowerValue != null) {
if (nodeProperty.isMultiple()) {
boolean match = false;
for (Value value: nodeProperty.getValues()) {
if ((">=".equals(lowerOperation) && value.getDouble() >= dLowerValue) ||
(!">=".equals(lowerOperation) && value.getDouble() > dLowerValue)) {
match = true;
break;
}
}
if (!match) return false;
} else if ((">=".equals(lowerOperation) && nodeProperty.getDouble() < dLowerValue) ||
(!">=".equals(lowerOperation) && nodeProperty.getDouble() <= dLowerValue)) {
return false;
}
}
if (upperValue != null) {
if (nodeProperty.isMultiple()) {
boolean match = false;
for (Value value: nodeProperty.getValues()) {
if (("<=".equals(upperOperation) && value.getDouble() <= dUpperValue) ||
(!"<=".equals(upperOperation) && value.getDouble() < dUpperValue)) {
match = true;
break;
}
}
if (!match) return false;
} else if (("<=".equals(upperOperation) && nodeProperty.getDouble() > dUpperValue) ||
(!"<=".equals(upperOperation) && nodeProperty.getDouble() >= dUpperValue)) {
return false;
}
}
}
}
} catch (ValueFormatException e) {
log.warn("Could not evaluate range: property = '" + property + "', node = '" + path + "'", e);
} catch (RepositoryException e) {
throw new RuntimeException("Could not evaluate range: property = '" + property + "', node = '" + path + "'", e);
}
return true;
}
}