com.day.cq.search.eval.TypePredicateEvaluator 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.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeIterator;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.query.Row;
import org.apache.felix.scr.annotations.Component;
import org.apache.jackrabbit.JcrConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.search.Predicate;
import com.day.cq.search.facets.FacetExtractor;
import com.day.cq.search.facets.extractors.DistinctValuesFacetExtractor;
/**
* Restricts results to a specific JCR node type, both primary node type or mixin type.
* This will also find subtypes of that node type. Note that repository search indexes
* need to cover the node types for efficient execution.
*
*
* Supports facet extraction. Will provide buckets for each unique type in the results.
*
*
Name:
* type
*
* Properties:
*
* - type
* - node type or mixin name to search for, for example
cq:Page
*
*
* @since 5.2
*/
@Component(metatype = false, factory = "com.day.cq.search.eval.PredicateEvaluator/type")
public class TypePredicateEvaluator extends AbstractPredicateEvaluator {
private static final Logger log = LoggerFactory.getLogger(TypePredicateEvaluator.class);
public static final String TYPE = "type";
protected static final String NO_SUCH_NODETYPE = TypePredicateEvaluator.class.getName() + ".no-such-nodetype.";
protected static final String NODETYPE_FOUND = TypePredicateEvaluator.class.getName() + ".nodetype-found.";
@Override
public String getXPathExpression(Predicate p, EvaluationContext context) {
if (!p.hasNonEmptyValue(TYPE)) {
return null;
}
final String typeName = p.get(TYPE);
List searchNodeTypes = new ArrayList();
try {
final NodeTypeManager nodeTypeManager = context.getSession().getWorkspace().getNodeTypeManager();
NodeType nodeType;
try {
nodeType = nodeTypeManager.getNodeType(typeName);
} catch (NoSuchNodeTypeException ne) {
log.warn("Node type '" + typeName + "' not found");
return null;
}
searchNodeTypes.add(nodeType);
searchNodeTypes.addAll(getDescendentNodeTypes(nodeType, nodeTypeManager));
} catch (RepositoryException e) {
log.debug("could not find child node types for '" + typeName + "'", e);
}
// enclose in parentheses as the result must be combinable with "and"
StringBuffer xpath = new StringBuffer();
xpath.append("(");
for (NodeType nt : searchNodeTypes) {
// containing more than just the "("
if (xpath.length() > 1) {
xpath.append(" or ");
}
if (nt.isMixin()) {
xpath.append("@").append(JcrConstants.JCR_MIXINTYPES);
} else {
xpath.append("@").append(JcrConstants.JCR_PRIMARYTYPE);
}
xpath.append(" = '").append(nt.getName()).append("'");
}
xpath.append(")");
return xpath.toString();
}
@Override
public boolean includes(Predicate p, Row row, EvaluationContext context) {
if (!p.hasNonEmptyValue(TYPE)) {
return true;
}
final String type = getType(p, context);
if (type == null) {
// node type does not exist
return false;
}
Node node = context.getNode(row);
try {
return node.isNodeType(type);
} catch (RepositoryException e) {
log.error("Problem while checking node for node type '" + p.get(TYPE) + "'", e);
}
return false;
}
/**
* Returns and validates the type from the predicate. If it is not an
* existing node type, it will return null
.
*/
public static String getType(Predicate p, EvaluationContext context) {
final String type = p.get(TYPE);
// quick fail if we noted earlier that this type does not exist
if (context.get(NO_SUCH_NODETYPE + type) != null) {
return null;
} else if (context.get(NODETYPE_FOUND + type) == null) {
// check if we checked the node type already
try {
final NodeTypeManager nodeTypeManager = context.getSession().getWorkspace().getNodeTypeManager();
try {
nodeTypeManager.getNodeType(type);
} catch (NoSuchNodeTypeException ne) {
log.warn("Node type '" + type + "' not found");
// mark non-existing
context.put(NO_SUCH_NODETYPE + type, true);
return null;
}
// mark node type found and valid
context.put(NODETYPE_FOUND + type, true);
} catch (RepositoryException e) {
log.error("Problem while checking node for node type '" + p.get(TYPE) + "'", e);
return null;
}
}
return type;
}
@Override
public boolean canXpath(Predicate p, EvaluationContext context) {
return true;
}
@Override
public boolean canFilter(Predicate p, EvaluationContext context) {
return true;
}
@Override
public String[] getOrderByProperties(Predicate p, EvaluationContext context) {
return new String[] { JcrConstants.JCR_PRIMARYTYPE, JcrConstants.JCR_MIXINTYPES };
}
@Override
public FacetExtractor getFacetExtractor(Predicate predicate, EvaluationContext context) {
return new DistinctValuesFacetExtractor(JcrConstants.JCR_PRIMARYTYPE, null, predicate.clone(), TYPE);
}
protected List getDescendentNodeTypes(NodeType nodeType, NodeTypeManager nodeTypeManager) throws RepositoryException {
List childNodeTypes = new ArrayList();
NodeTypeIterator allTypes = nodeTypeManager.getAllNodeTypes();
while (allTypes.hasNext()) {
NodeType nt = allTypes.nextNodeType();
if (Arrays.asList(nt.getSupertypes()).contains(nodeType)) {
childNodeTypes.add(nt);
}
}
return childNodeTypes;
}
}