com.day.cq.search.facets.extractors.PropertyFacetExtractor 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.facets.extractors;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import com.day.cq.search.facets.FacetExtractor;
/**
* PropertyFacetExtractor
is a base class for facet extractors that
* work on a certain property (incl. relative paths to properties in sub-nodes),
* specified by the parameter propertyRelPath
in the constructor.
* In addition, subclasses can implement {@link #filter(List, ValueFactory)} for
* further filtering of the list of values.
*
* @since 5.2
*/
public abstract class PropertyFacetExtractor implements FacetExtractor {
/**
* Empty list of properties.
*/
protected static final List EMPTY_PROPERTY_LIST = Collections.emptyList();
/**
* Relative path to the property that provides the value for the facet.
*/
protected final String propertyRelPath;
public PropertyFacetExtractor(String propertyRelPath) {
this.propertyRelPath = propertyRelPath;
}
/**
* Called for each value found in a node of the result and that matches the
* relative property path. This can be multiple values per node as it could
* be a multi-value property or if multiple properties match the relative
* property path pattern.
*
* @param value a value to check in which bucket it fits
* @throws RepositoryException
*/
protected abstract void handleValue(Value value) throws RepositoryException;
/**
* Filters the values
by applying the filter of the definition
* associated with this facet.
*
* @param values the values to filter.
* @param vf the value factory.
* @return the filtered values.
* @throws RepositoryException if an error occurs while reading the values.
*/
protected abstract List filter(List values, ValueFactory vf) throws RepositoryException;
public void handleNode(Node node) throws RepositoryException {
List values = getValues(node);
for (Value value : values) {
handleValue(value);
}
}
/**
* Gets the values of this facet for the provided node
.
*
* @param node the node.
* @return the values of this facet.
* @throws RepositoryException if an error occurs while reading from the node.
*/
protected List getValues(Node node) throws RepositoryException {
ValueFactory vf = node.getSession().getValueFactory();
List values = null;
Iterator props = getProperties(node, propertyRelPath);
if (props.hasNext()) {
boolean isBinary = false;
values = new ArrayList();
while (props.hasNext()) {
Property p = props.next();
if (p.getType() == PropertyType.BINARY) {
isBinary = true;
long[] lengths;
if (p.getDefinition().isMultiple()) {
lengths = p.getLengths();
} else {
lengths = new long[]{p.getLength()};
}
for (long len : lengths) {
values.add(vf.createValue(len));
}
} else if (p.getDefinition().isMultiple()) {
values.addAll(Arrays.asList(p.getValues()));
} else {
values.add(p.getValue());
}
}
// special case for binaries, always return lengths
if (isBinary) {
return values;
}
} else {
// properties are empty when we only look at node paths (for using the nodePathFilter)
try {
if (node.hasNode(propertyRelPath)) {
values = new ArrayList();
values.add(node.getSession().getValueFactory().createValue(
node.getNode(propertyRelPath).getPath()));
}
} catch (RepositoryException e) {
// ignore
}
}
if (values == null) {
values = Collections.emptyList();
}
return filter(values, vf);
}
/**
* Returns the properties below node
that match the
* pathPattern
.
*
* @param node the start node.
* @param pathPattern a relative path pattern. See
* {@link Node#getProperties(String)} for a definition of a pattern.
*
* @return the properties that match the path pattern.
* @throws RepositoryException if an error occurs while reading from the
* repository.
*/
private static Iterator getProperties(Node node, String pathPattern)
throws RepositoryException {
if (pathPattern == null || pathPattern.equals(".")) {
return EMPTY_PROPERTY_LIST.iterator();
}
List nodes = new ArrayList();
List properties = new ArrayList();
nodes.add(node);
String[] namePattern = pathPattern.split("/");
for (int i = 0; i < namePattern.length; i++) {
if (i == namePattern.length - 1) {
for (Node n : nodes) {
for (PropertyIterator pIt = n.getProperties(namePattern[i]); pIt.hasNext();) {
properties.add(pIt.nextProperty());
}
}
} else {
List children = new ArrayList();
for (Node n : nodes) {
for (NodeIterator nIt = n.getNodes(namePattern[i]); nIt.hasNext();) {
children.add(nIt.nextNode());
}
}
nodes = children;
}
}
return properties.iterator();
}
}