blob: ca00de0229f8752533e3ae5ed82566881671bb4f [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.jackrabbit.oak.spi.query;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.jcr.PropertyType;
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* The filter for an index lookup that contains a number of restrictions that
* are combined with AND. Possible restrictions are a property restriction, a
* path restriction, a node type restriction, and a fulltext restriction.
* <p>
* A property restriction could be that the property must exist, or that the
* property value has to be within a certain range.
* <p>
* A path restriction could be a restriction to a certain subtree, a parent of a
* certain path, or equality to a certain path.
*/
public interface Filter {
/**
* Get the list of property restrictions, if any. Each property may contain
* multiple restrictions, for example x=1 and x=2. For this case, only
* multi-valued properties match that contain both 1 and 2.
*
* @return the conditions (an empty collection if not used)
*/
Collection<PropertyRestriction> getPropertyRestrictions();
/**
* Get the fulltext search conditions, if any.
*
* @return the conditions (an empty collection if not used)
*/
@Deprecated
Collection<String> getFulltextConditions();
/**
* Get the fulltext search condition expression, if any.
*
* @return the condition (null if none)
*/
FullTextExpression getFullTextConstraint();
QueryLimits getQueryLimits();
/**
* check whether a certain (valid) path is accessible (can be read) from the user associated with the query Session
* @param path a valid JCR path
* @return <code>true</code> if path can be read by the calling user, <code>false</code> otherwise.
*/
boolean isAccessible(String path);
/**
* Whether the filter contains a native condition.
*
* @return true if it does
*/
boolean containsNativeConstraint();
/**
* Get the most restrictive property restriction for the given property, if
* any.
*
* @param propertyName the property name
* @return the first restriction, or null if there is no restriction for
* this property
*/
PropertyRestriction getPropertyRestriction(String propertyName);
/**
* Get the all property restriction for the given property.
*
* @param propertyName the property name
* @return the list of restrictions (possibly empty, never null)
*/
List<PropertyRestriction> getPropertyRestrictions(String propertyName);
/**
* Get the path restriction type.
*
* @return the path restriction type
*/
PathRestriction getPathRestriction();
/**
* Get the path, or "/" if there is no path restriction set.
*
* @return the path
*/
String getPath();
/**
* Get the plan for the path.
*
* @return the plan
*/
String getPathPlan();
/**
* Returns the name of the filter node type.
*
* @return nodetype name
*/
@Nullable
String getNodeType();
/**
* Checks whether nodes of all types can match this filter.
*
* @return {@code true} iff there are no type restrictions
*/
boolean matchesAllTypes();
/**
* Returns the names of the filter node type and all its supertypes.
*
* @return supertype name
*/
@NotNull
Set<String> getSupertypes();
/**
* Returns the names of all matching primary node types.
*
* @return primary node type names
*/
@NotNull
Set<String> getPrimaryTypes();
/**
* Returns the names of all matching mixin node types.
*
* @return mixin node type names
*/
@NotNull
Set<String> getMixinTypes();
/**
* Get the complete query statement. The statement should only be used for
* logging purposes.
*
* @return the query statement (possibly null)
*/
@Nullable
String getQueryStatement();
/**
* If the filter condition can not possibly match any row, due to a
* contradiction in the query (for example "x=1 and x=2").
*
* @return true if the filter condition can not match any row
*/
boolean isAlwaysFalse();
/**
* A restriction for a property.
*/
class PropertyRestriction {
/**
* The name of the property.
*/
public String propertyName;
/**
* The first value to read, or null to read from the beginning.
*/
public PropertyValue first;
/**
* Whether values that match the first should be returned.
*/
public boolean firstIncluding;
/**
* The last value to read, or null to read until the end.
*/
public PropertyValue last;
/**
* Whether values that match the last should be returned.
*/
public boolean lastIncluding;
/**
* Whether this is a like constraint. in this case only the 'first'
* value should be taken into consideration
*/
public boolean isLike;
/**
* A list of possible values, for conditions of the type
* "x=1 or x=2 or x=3".
*/
public List<PropertyValue> list;
/**
* The property type, if restricted.
* If not restricted, this field is set to PropertyType.UNDEFINED.
*/
public int propertyType = PropertyType.UNDEFINED;
public boolean isNullRestriction() {
return first == null && last == null && list == null && lastIncluding && firstIncluding;
}
public boolean isNotNullRestriction() {
return first == null && last == null && list == null && !lastIncluding && !firstIncluding;
}
@Override
public String toString() {
return (toStringFromTo() + " " + toStringList()).trim();
}
private String toStringList() {
if (list == null) {
return "";
}
StringBuilder buff = new StringBuilder("in(");
int i = 0;
for (PropertyValue p : list) {
if (i++ > 0) {
buff.append(", ");
}
buff.append(p.toString());
}
buff.append(')');
return buff.toString();
}
private String toStringFromTo() {
if (isNullRestriction()) {
return "is null";
} else if (isNotNullRestriction()) {
return "is not null";
}
String f = first == null ? "" : first.toString();
String l = last == null ? "" : last.toString();
if (f.equals(l)) {
return f;
}
String fi = first == null ? "" : (firstIncluding ? "[" : "(");
String li = last == null ? "" : (lastIncluding ? "]" : ")");
return fi + f + ".." + l + li;
}
/**
* How restrictive a condition is.
*
* @return 0 for "is not null", 10 for equality, and 5 for everything
* else
*/
public int sortOrder() {
if (first == null && last == null) {
if (list == null) {
return 0;
}
return 5;
}
if (first == last) {
return 10;
}
return 5;
}
@Override
public int hashCode() {
// generated code (Eclipse)
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + (firstIncluding ? 1231 : 1237);
result = prime * result + (isLike ? 1231 : 1237);
result = prime * result + ((last == null) ? 0 : last.hashCode());
result = prime * result + (lastIncluding ? 1231 : 1237);
result = prime * result + ((list == null) ? 0 : list.hashCode());
result = prime * result +
((propertyName == null) ? 0 : propertyName.hashCode());
result = prime * result + propertyType;
return result;
}
@Override
public boolean equals(Object obj) {
// generated code (Eclipse)
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PropertyRestriction other = (PropertyRestriction) obj;
if (first == null) {
if (other.first != null) {
return false;
}
} else if (!first.equals(other.first)) {
return false;
}
if (firstIncluding != other.firstIncluding) {
return false;
}
if (isLike != other.isLike) {
return false;
}
if (last == null) {
if (other.last != null) {
return false;
}
} else if (!last.equals(other.last)) {
return false;
}
if (lastIncluding != other.lastIncluding) {
return false;
}
if (list == null) {
if (other.list != null) {
return false;
}
} else if (!list.equals(other.list)) {
return false;
}
if (propertyName == null) {
if (other.propertyName != null) {
return false;
}
} else if (!propertyName.equals(other.propertyName)) {
return false;
}
if (propertyType != other.propertyType) {
return false;
}
return true;
}
}
/**
* The path restriction type.
*/
enum PathRestriction {
/**
* All nodes.
*/
NO_RESTRICTION("*"),
/**
* A parent of this node.
*/
PARENT("/.."),
/**
* This exact node only.
*/
EXACT(""),
/**
* All direct child nodes.
*/
DIRECT_CHILDREN("/*"),
/**
* All direct and indirect child nodes (excluding the node with the
* given path).
*/
ALL_CHILDREN("//*");
private final String name;
PathRestriction(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
Filter EMPTY_FILTER = new Filter() {
private final QueryLimits EMPTY_LIMITS = new QueryLimits() {
@Override
public long getLimitInMemory() {
return Long.MAX_VALUE;
}
@Override
public long getLimitReads() {
return Long.MAX_VALUE;
}
@Override
public boolean getFullTextComparisonWithoutIndex() {
return false;
}
@Override
public boolean getFailTraversal() {
return false;
}
};
@Override
public Collection<PropertyRestriction> getPropertyRestrictions() {
return Collections.emptyList();
}
@Override
public Collection<String> getFulltextConditions() {
return Collections.emptyList();
}
@Override
public FullTextExpression getFullTextConstraint() {
return null;
}
@Override
public QueryLimits getQueryLimits() {
return EMPTY_LIMITS;
}
@Override
public boolean isAccessible(String path) {
return false;
}
@Override
public boolean containsNativeConstraint() {
return false;
}
@Override
public PropertyRestriction getPropertyRestriction(String propertyName) {
return null;
}
@Override
public List<PropertyRestriction> getPropertyRestrictions(String propertyName) {
return Collections.emptyList();
}
@Override
public PathRestriction getPathRestriction() {
return PathRestriction.NO_RESTRICTION;
}
@Override
public String getPath() {
return PathUtils.ROOT_PATH;
}
@Override
public String getPathPlan() {
return PathRestriction.NO_RESTRICTION.toString();
}
@Nullable
@Override
public String getNodeType() {
return null;
}
@Override
public boolean matchesAllTypes() {
return false;
}
@NotNull
@Override
public Set<String> getSupertypes() {
return Collections.emptySet();
}
@NotNull
@Override
public Set<String> getPrimaryTypes() {
return Collections.emptySet();
}
@NotNull
@Override
public Set<String> getMixinTypes() {
return Collections.emptySet();
}
@Nullable
@Override
public String getQueryStatement() {
return null;
}
@Override
public boolean isAlwaysFalse() {
return false;
}
};
}