com.day.cq.search.PredicateGroup Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* A PredicateGroup
is a {@link Predicate} that represents a list
* of {@link Predicate Predicates} (following the composite pattern). This
* allows to build predicate trees for reflecting complex queries that include
* sub-terms.
*
*
* The predicates in a group are by default all required to match, ie. they will
* be combined with "AND" in a lower-level query language, which is indicated by
* {@link #allRequired()} returning true. If {@link #setAllRequired(boolean)} is
* called with false
, or if the parameter or
is set to
* true
, the child predicates will be combined with "OR", ie. only
* one must match for the whole group to match.
*
*
* If the parameter not
is set to true
, the result of
* this group will be negated. See also {@link #isNegated()} and
* {@link #setNegated(boolean)}.
*
*
* This class extends both the {@link Predicate} class and implements the
* {@link List} interface, backed by a standard {@link ArrayList} internally.
*
*
* The standard type name for predicate groups is given by {@link #TYPE} (
* {@value PredicateGroup#TYPE}), which is also used when using the default
* constructor.
*
* @since 5.2
*/
public class PredicateGroup extends Predicate implements List {
public static final String TYPE = "group";
private List predicates = new ArrayList();
/**
* Creates this predicate group with the group type
* {@value #TYPE}
, and a predicate name of null
.
* Use this constructor when the name should be deducted automatically (see
* {@link #getName()}) or for the root group of a predicate tree, because
* the name must be null
for that case.
*/
public PredicateGroup() {
super(null, PredicateGroup.TYPE);
}
/**
* Creates this predicate group with the given name and the group type
* {@value #TYPE}
, using the
* {@link Predicate#Predicate(String, String)} constructor. If you create a
* root group of a predicate tree, the name must be null
(you
* can use the default constructor {@link #PredicateGroup()} for that).
*/
public PredicateGroup(String name) {
super(name, PredicateGroup.TYPE);
}
/**
* Converts a map with predicates and their parameters into a predicate
* tree. Accepts a map with strings as keys and either simple strings as
* values or string arrays as values. In the array case, the first value
* will be chosen.
*
*
* Same as {@link PredicateConverter#createPredicates(Map)}.
*/
public static PredicateGroup create(Map predicateParameterMap) {
return PredicateConverter.createPredicates(predicateParameterMap);
}
/**
* Returns an URL query part containing the given group. This is the same
* mapping as used in {@link #createMap(PredicateGroup)} and
* {@link #createPredicates(Map)}. For example, the returned value could be:
* type=cq:Page&path=/content
. Note that this won't be a
* complete URL, just a list of parameters for an URL query part. The keys
* and values will be properly escaped for use in an URL.
*
*
* Same as {@link PredicateConverter#toURL(PredicateGroup)}.
*/
public String toURL() {
return PredicateConverter.toURL(this);
}
/**
* Returns whether all predicates are combined with "AND", ie. only nodes
* are found that match all predicates in this group. The default value is
* true
(AND):
*
* @return true
for "AND" (default), false
for "OR"
*/
public boolean allRequired() {
// default is AND, hence we use the "inverse" OR flag
return !getBool("or");
}
/**
* Sets whether all predicates are combined with "AND", ie. only nodes are
* found that match all predicates in this group, or if they are combined
* with "OR".
*
* @param all
* true
for "AND", false
for "OR"
*/
public void setAllRequired(boolean all) {
// invert since we set "or" here
set("or", all ? "false" : "true");
}
/**
* Returns whether the result of this predicate group should be negated. Ie.
* only nodes that do not match this group should be included in the
* results. The default value is false
.
*
* @return true
for exclusive, false
for inclusive
* (default)
*
* @since 5.5
*/
public boolean isNegated() {
return getBool("not");
}
/**
* Sets whether the result of this group should be negated.
*
* @param not
* true
if the group should be negated,
* false
if not (default)
*
* @since 5.5
*/
public void setNegated(boolean not) {
set("not", not ? "true" : "false");
}
/**
* Returns a certain predicate by its {@link Predicate#getName() name}.
*/
public Predicate getByName(String name) {
for (Predicate p: predicates) {
if (ObjectUtils.equals(p.getName(), name)) {
return p;
}
}
return null;
}
/**
* Returns a certain predicate by its {@link Predicate#getPath() path},
* relative to this predicate.
*/
public Predicate getByPath(String path) {
// eg. "group.1_group.type" => "group" + "1_group.type"
String[] splits = path.split("\\.", 2);
Predicate predicate = getByName(splits[0]);
if (predicate != null) {
if (predicate instanceof PredicateGroup) {
// PredicateGroup
if (splits.length > 1) {
return ((PredicateGroup) predicate).getByPath(splits[1]);
}
} else {
// Predicate
return predicate;
}
}
// path not found
return null;
}
/**
* Clones this predicate group so that the returned clone can be used
* completely independently from this original. All child predicates
* will hence also be cloned.
*/
@Override
public PredicateGroup clone() {
return clone(false);
}
/**
* Clones this predicate group so that the returned clone can be used
* completely independently from this original. All child predicates will
* hence also be cloned. A new name for the clone can be passed.
*
* @param resetName
* whether to reset the name and child predicate names to
* null
so that they will be automatically
* deducted (see {@link #getName()})
*/
@Override
public PredicateGroup clone(boolean resetName) {
PredicateGroup clone = (PredicateGroup) super.clone(resetName);
clone.predicates = new ArrayList();
for (Predicate p : predicates) {
Predicate pc = p.clone(resetName);
pc.setParent(clone);
clone.predicates.add(pc);
}
return clone;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (!(obj instanceof PredicateGroup))
return false;
PredicateGroup other = (PredicateGroup) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(predicates, other.predicates)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 31)
.appendSuper(super.hashCode())
.append(predicates)
.toHashCode();
}
// -------------------------------------------< misc >
private static int indent = 0;
/**
* Overwrites the standard {@link Object#toString()} implementation and
* returns a debug-friendly string including all sub predicates (via their
* {@link Predicate#toString() toString()} method). The final string is
* multi-lined and indented for easy readability of the inherent tree
* structure.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(super.toString());
buffer.append("[\n");
indent += 4;
for (Predicate p: this) {
appendIndent(buffer);
buffer.append("{").append(p.toString()).append("}\n");
}
indent = (indent <= 4 ? 0 : indent - 4);
appendIndent(buffer);
buffer.append("]");
return buffer.toString();
}
private void appendIndent(StringBuffer buffer) {
for (int i = 0; i < indent; i++) {
buffer.append(" ");
}
}
protected void setMeAsParent(Predicate element) {
element.setParent(this);
}
protected void unsetParent(Predicate element) {
element.setParent(null);
}
// ------------------------------------------------< List interface >
public boolean add(Predicate o) {
setMeAsParent(o);
return predicates.add(o);
}
public void add(int index, Predicate element) {
setMeAsParent(element);
predicates.add(index, element);
}
public boolean addAll(Collection extends Predicate> c) {
for (Predicate p : c) {
setMeAsParent(p);
}
return predicates.addAll(c);
}
public boolean addAll(int index, Collection extends Predicate> c) {
for (Predicate p : c) {
setMeAsParent(p);
}
return predicates.addAll(index, c);
}
public void clear() {
for (Predicate p : predicates) {
unsetParent(p);
}
predicates.clear();
}
public boolean contains(Object o) {
return predicates.contains(o);
}
public boolean containsAll(Collection> c) {
return predicates.containsAll(c);
}
public Predicate get(int index) {
return predicates.get(index);
}
public int indexOf(Object o) {
return predicates.indexOf(o);
}
public boolean isEmpty() {
return predicates.isEmpty();
}
public Iterator iterator() {
return predicates.iterator();
}
public int lastIndexOf(Object o) {
return predicates.lastIndexOf(o);
}
public ListIterator listIterator() {
return predicates.listIterator();
}
public ListIterator listIterator(int index) {
return predicates.listIterator(index);
}
public boolean remove(Object o) {
unsetParent((Predicate) o);
return predicates.remove(o);
}
public Predicate remove(int index) {
Predicate p = predicates.remove(index);
unsetParent(p);
return p;
}
public boolean removeAll(Collection> c) {
for (Object o : c) {
unsetParent((Predicate) o);
}
return predicates.removeAll(c);
}
public boolean retainAll(Collection> c) {
Iterator iter = iterator();
while (iter.hasNext()) {
Predicate p = iter.next();
if (!c.contains(p)) {
unsetParent(p);
}
}
return predicates.retainAll(c);
}
public Predicate set(int index, Predicate element) {
setMeAsParent(element);
return predicates.set(index, element);
}
public int size() {
return predicates.size();
}
public List subList(int fromIndex, int toIndex) {
return predicates.subList(fromIndex, toIndex);
}
public Object[] toArray() {
return predicates.toArray();
}
public T[] toArray(T[] a) {
return predicates.toArray(a);
}
}