All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.search.Predicate Maven / Gradle / Ivy

The newest version!
/*
 * 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.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import com.day.cq.search.eval.PredicateEvaluator;
import com.day.cq.search.result.SearchResult;

/**
 * A Predicate is a single constraint for a {@link Query}. It is a
 * pure data model object, consisting of a parameter map based on key-value
 * string pairs.
 * 
 * 

* Each {@link Predicate} has a type ({@link #getType()}) that is used to find * the right {@link PredicateEvaluator} that will handle this predicate and eg. * translate it into an XPath statement. * *

* Using the composite pattern, the subclass {@link PredicateGroup} allows to * group multiple predicates into one. This allows the query to actually consist * of a predicate tree and reflects more complex queries that include sub-terms. * The methods {@link #getName()}, {@link #getPath()} and {@link #getParent()} * return that hierarchy information. The name/path is important, because facets * will be returned in a map with the appropriate predicate path as key (see * {@link SearchResult#getFacets()}). * *

* The parameters are set via the {@link #set(String, String)} method and * retrieved via {@link #get(String)}, {@link #get(String, String)} or * {@link #getParameters()}. Predicates are also {@link Cloneable}, so that it * is easy to copy them. * * @since 5.2 */ public class Predicate implements Cloneable { public static final String PARAM_OFFSET = "offset"; public static final String PARAM_LIMIT = "limit"; public static final String PARAM_EXCERPT = "excerpt"; public static final String PARAM_FACET_STRATEGY = "facetStrategy"; /** * How to handle traversals - translated into Query Option 'traversal'. * Valid values = ok|fail|warn *

     * p.traversal=ok
     * 
*/ public static final String PARAM_OPTIONS_TRAVERSAL = "traversal"; public static final String TRAVERSAL_OK = "ok"; public static final String TRAVERSAL_FAIL = "fail"; public static final String TRAVERSAL_WARN = "warn"; /** * Translated into Query Option 'index tag' *
     * p.indexTag=tagName
     * 
*/ public static final String PARAM_OPTIONS_INDEXTAG = "indexTag"; /** * If true, this allows the implementation to optimize the query and return * just a guessed {@link SearchResult#getTotalMatches() count}. Defaults to * false, in which case the total is always accurate. * * @since 5.4 */ public static final String PARAM_GUESS_TOTAL = "guessTotal"; public final static String ORDER_BY = "orderby"; /** * Parameter on {@code orderby} to control whether the sort order is ascending * (default) or descending. Possible values are {@code asc} and {@code desc}. *
     * orderby.sort=desc
     * 
*/ public final static String PARAM_SORT = "sort"; public final static String SORT_ASCENDING = "asc"; public final static String SORT_DESCENDING = "desc"; /** * Parameter on {@code orderby} to control whether sorting is case insensitive or not. * Only the value {@code ignore} is supported, in which case "a" comes before "B". * If empty or left out, sorting is case sensitive, e.g. "B" comes before "a". *
     * orderby.case=ignore
     * 
*/ public final static String PARAM_CASE = "case"; public final static String IGNORE_CASE = "ignore"; final private String type; private String name; private PredicateGroup parent; private Map params = new HashMap(); private boolean ignore = false; /** * Creates a {@link Predicate} of the given type. Note that the type * cannot be changed later. The name will be deducted automatically, * see {@link #getName()}. Initially no parameters will be set and * no parent will be present. * * @param type * predicate type name for finding the right * {@link PredicateEvaluator} */ public Predicate(String type) { this(null, type); } /** * Creates a {@link Predicate} with the given name and type. Note that name * and type cannot be changed later. Initially no parameters will be set and * no parent will be present. * *

* The name should not be null - this case is reserved for a * root {@link PredicateGroup} (using * {@link PredicateGroup#PredicateGroup()}). * * @param name * identifying name for this predicate * @param type * predicate type name for finding the right * {@link PredicateEvaluator} */ public Predicate(String name, String type) { this.name = name; this.type = type; } /** * Returns the predicate type name for finding the right * {@link PredicateEvaluator}. */ public String getType() { return type; } /** * Returns the name of this predicate. The name is used to allow round-trip * serialization of predicate trees (where the order is encoded in the * names) and for identifying predicates in the * {@link SearchResult#getFacets() facet map}, in logging or other debug * output. * *

* When a predicate is included in {@link PredicateGroup}, the names of the * parent predicates will make up the {@link #getPath() path}, eg. * parent.child.grandchild. The name must not be changed after * the predicate is passed to a {@link Query}. * *

* If no name was set previously, it will be automatically created. If this * predicate is part of a group, it will get a name of the form "N_type" * where N is the 1-based index of its position in the parent group and * "type" is it's {@link #getType() type}. If it does not have a parent group, * the name will only consist of the type. * * @return identifying name for this predicate (can be null if * no name was set) */ public String getName() { if (name == null) { if (parent == null) { // ROOT node has null name by convention return null; } // check for other siblings if (parent.size() > 0) { // need to prefix with index for unique name int index = parent.indexOf(this) + 1; return index + "_" + getType(); } else { // type as name is enough return getType(); } } return name; } /** * Returns the path in a predicate tree of {@link PredicateGroup * PredicateGroups} to this predicate, eg. * parent.child.grandchild. This can be null if no * name was set. The path is used for identifying predicates in the * {@link SearchResult#getFacets() facet map}, in logging or other debug * output. */ public String getPath() { if (parent != null) { String path = parent.getPath(); if (path != null) { return path + "." + getName(); } else { return getName(); } } else if (getName() == null) { return null; } else { return getName(); } } /** * Returns the value for the given parameter name or null if * that parameter is not set. Parameters always have {@link String} values. */ public String get(String parameterName) { return params.get(parameterName); } /** * Returns the value for the given parameter name or the given default value * if that parameter is not set. Parameters always have {@link String} * values. */ public String get(String parameterName, String defaultValue) { if (hasNonEmptyValue(parameterName)) { return get(parameterName); } else { return defaultValue; } } /** * Returns the boolean value for the given parameter name or * false if that parameter is not set, ie. it assumes * false as the default of the boolean parameter. * *

* Since actual parameter values are strings, it is considered * true if the string value is either "true" or "on" (used by * HTTP forms for checkboxes). */ public boolean getBool(String parameterName) { if (hasNonEmptyValue(parameterName)) { String value = get(parameterName); return "on".equals(value) || "true".equals(value); } return false; } /** * Sets the parameter 'parameterName' to the value given by 'value'. * Parameters have always {@link String} values. * * @return returns itself for simple one-liners: * group.add(new Predicate("mytype", "type").set("type", "nt:file")); */ public Predicate set(String parameterName, String value) { params.put(parameterName, value); return this; } /** * Returns true when there is a parameter present with the * given name and if the string value is not empty. Parameters always have * {@link String} values. */ public boolean hasNonEmptyValue(String parameterName) { String value = get(parameterName); return (value != null && value.length() > 0); } /** * Returns an unmodifiable map of all parameters and their values. */ public Map getParameters() { return Collections.unmodifiableMap(params); } /** * This is used only during evaluation and marks this predicate as * "invisible" for any {@link PredicateEvaluator} that will encounter it. * Don't use that method when creating a query. * * @param ignore * true if this predicate should be ignored by * evaluators (default is false) */ public void setIgnored(boolean ignore) { this.ignore = ignore; } /** * This is used only during evaluation and indicates that this predicate is * marked as "invisible" for any {@link PredicateEvaluator} that will * encounter it. This method has no use for clients of the querybuilder API. * * @return true if this predicate should be ignored by * evaluators (default is false) * */ public boolean ignored() { return this.ignore; } /** * Clones this predicate so that the returned clone can be used completely * independently from this original. Same as {@link #clone(boolean) * clone(false)}. */ @Override public Predicate clone() { return clone(false); } /** * Clones this predicate so that the returned clone can be used completely * independently from this original. Allows for automatic reset of the name. * * @param resetName * whether to reset the name to null so that they * will be automatically deducted (see {@link #getName()}) */ public Predicate clone(boolean resetName) { // we need to implement clone to make it public (Object's clone is protected) try { Predicate clone = (Predicate) super.clone(); // loose parent relationship - if a tree is cloned, the parent's clone method // will take care of re-setting the parent clone.parent = null; clone.params = new HashMap(); for (String key : params.keySet()) { clone.params.put(key, params.get(key)); } if (resetName) { clone.name = null; } return clone; } catch (CloneNotSupportedException e) { // cannot happen since Predicate implements Cloneable throw new InternalError(e.toString()); } } @Override public boolean equals(Object obj) { if (obj == null) return false; if (obj == this) return true; if (!(obj instanceof Predicate)) return false; Predicate other = (Predicate) obj; return new EqualsBuilder() .append(type, other.type) .append(name, other.name) .append(params, other.params) .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder(17, 31) .append(type) .append(name) .append(params) .toHashCode(); } // -------------------------------------------< protected > /** * Used by {@link PredicateGroup} to store the hierarchy information when * adding a predicate (through eg. {@link PredicateGroup#add(Predicate)}). * Normally there is no reason to call this method, hence it is * protected. * * @param parent * parent predicate group to set */ protected void setParent(PredicateGroup parent) { this.parent = parent; } // -------------------------------------------< misc > /** * Overwrites the standard {@link Object#toString()} implementation and * returns a debug-friendly string representation of the predicate. */ public String toString() { StringBuffer buffer = new StringBuffer(); String name = getName(); if (name == null) { name = "ROOT"; } buffer.append(name).append("=").append(getType()).append(": "); Map allParams = new HashMap(params); Iterator keyIter = allParams.keySet().iterator(); while (keyIter.hasNext()) { final String key = keyIter.next(); buffer.append(key).append("=").append(allParams.get(key)); if (keyIter.hasNext()) { buffer.append(", "); } } return buffer.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy